2017-02-04 03:45 AM
Hello all,
i am using a stm32f103c8t6 device, clocked at 72 MHZ, the periph clock for adc is 12MHZ ( 72/6).
Using adc injected function with sample time configured at ADC_SampleTime_1Cycles5
Timer 1 is generating a pwm wave on channel 4 ( CC4), and the cc4 signal is feed out trough TRGO and onto the ADC injection trigger input.
Till here everything works as expected, i have the correct voltage when reading the injection.
My ''without USART'' ADC interrupt handler.... looks like this , on the logic analyzer judging by the gpio toogle time, this routine runtime takes arround 1us to run.
void ADC1_2_IRQHandler(void)
{ if(ADC_GetITStatus(ADC1,ADC_IT_JEOC)){ /* Set PC.06 pin */ GPIOB->BRR = GPIO_Pin_11; // reset GPIOB->BSRR = GPIO_Pin_11;// set myadc = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1); ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);GPIOB->BRR = GPIO_Pin_11; // reset
}}But... i want to send the ADC value to my pc using usart connection... so i had some usart function inserted into the adc jeoc event....
So after each injection end of conversion... i send the data via usart at a baudrate of 460800bps... but i want the full 16bit value to be sent to the pc...
Ok said and done, the adc channel is tied to a 3.3v signal, on the usart i have 4093 decimal which is corect if i do the math...
But the problem which occures is the increase of adc irq handler runtime from 1us to 100us which is huge
.... and its screwing up my pwm signals ( see screenshot bellow)The adc channel is reading a shunt resistor which is coming from a 3 phase FET stage for a bldc, so i need feedback to the pc as fast as posible....
For example if i send usart to the pc which takes 100us... in this time i will have many pwm pulses where i can have overcurrent fault....
So i need to send feedback as fast as posible when reading the first pwm pulse on each of the 3 phases (or 3 pwm high side signals)
Is it posible to send usart data faster? without afecting the adc irq timing? Some ideas would be wellcomed
Thanks
2017-02-04 04:43 AM
Don't put blocking USART code in the IRQ Handler. Put it in a buffer served by the USART TXE IRQ.
2017-02-04 05:01 AM
Hello Clive
i was thinking of filling a variable inside the adc handler, and from there DMA to flush the variable data to the usart tx buffer, and send it out. Is it posible?
2017-02-04 06:33 AM
Yes, but you'd still need to ensure that the DMA buffer has vacated before starting another, or queue one up. The bandwidth will be limited by the USART baud rate.
2017-02-04 08:02 AM
Ok... so i am guessing either i use DMA or using USART to handle the events.... i will get the same result... but it will not afect the execution speed of the interrupt handlers...
Saying so i had enabled the TXE it from usart and ending with the following code
What do you think of the aproach bellow? ( also listed a logic analyze trace)
TXE IRQ sets a flag when the data can be sent via USART from main program execution & disables TXE IRQ
After the data is sent, the TXE IRQ is re-enabled again
void USART1_IRQHandler(void){ if(USART_GetITStatus(USART1,USART_IT_TXE) != RESET){ USART_ClearITPendingBit(USART1, USART_IT_TXE); GPIOB->BRR = GPIO_Pin_9; // reset GPIOB->BSRR = GPIO_Pin_9;// set uflag=1; // set flag for sending data from main programUSART_ITConfig(USART1, USART_IT_TXE, DISABLE); // disable TX interrupt } }void ADC1_2_IRQHandler(void){ if(ADC_GetITStatus(ADC1,ADC_IT_JEOC)){ /* Set PC.06 pin */ GPIOB->BRR = GPIO_Pin_11; // reset GPIOB->BSRR = GPIO_Pin_11;// set myadcz[1] = ADC_GetInjectedConversionValue(ADC1, ADC_InjectedChannel_1); // store ADC result in variable ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);GPIOB->BRR = GPIO_Pin_11; // reset }}/ ******* main program execution ****************/
int main(void){
while(1) {
if(uflag==1){ // IF flag was set in the USART1 TXE interrupt
uflag=2; UART_SendInt0(USART1, myadcz[1]); // send data while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET ); // wait for TX register to empty UART_SendChar(USART1,'-'); // add a separator between values while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET ); // wait for TX register to empty GPIOB->BRR = GPIO_Pin_9; // reset USART_ITConfig(USART1,USART_IT_TXE, ENABLE); // enable back the USART TXE interrupt }}
}