cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f103 - minimize delay due to usart transfer

Bogdan
Senior
Posted on February 04, 2017 at 12:45

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

}

}0690X00000606FBQAY.png

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)0690X00000606DuQAI.png

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

4 REPLIES 4
Posted on February 04, 2017 at 13:43

Don't put blocking USART code in the IRQ Handler. Put it in a buffer served by the USART TXE IRQ. 

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Bogdan
Senior
Posted on February 04, 2017 at 14:01

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?

Posted on February 04, 2017 at 14:33

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.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Bogdan
Senior
Posted on February 04, 2017 at 17:02

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

0690X00000606FaQAI.png

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 program

USART_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

}

}

}