cancel
Showing results for 
Search instead for 
Did you mean: 

Erratic USART behaviour using KEIL 5 Compiler

glenn0010
Associate III

Hi All,

I have a project that currently has a blinky, 2 ADC channel on DMA circular which were successfully working .

I have now implemented the USART2 on IRQ on my STM32F302 Nucleo. The USART2 is running at 32Mhz and 9600 baud. I have set up the USARt to echo back what I send from the PC.

As soon as I tried to implement the UART I started having issues.

1 - The characters echoed are not what I sent from my PC. I have tried changing the compiler setting in Keil 5. I changed the optimizations settings on the C/C++ tab from Level 0 to default. This helped somewhat but I still get back some random characters.

Furthermore, when I set it to default I cannot debug properly as the debugger seems to get stuck at some lines.

2 - My blinky also stops working which is odd

/*---------------------------------------------------------------------------------------------------------------
 
12/5/2019
 
SysCroeClock = 64Mhz
 
Blinky
ADC scaninng 2 channels continously in DMA Mode 1.5 conversiion cycles at 64Mhz
UART2 with interrupt running on clock of 32MHz  at 9600 baud
---------------------------------------------------------------------------------------------------------------*/
 
 
 
 
#include "stm32f302x8.h"
 //----------------- Gloobal Variables -------------------------------------------------------------------------
uint16_t ADC_Samples[2] = {0,0};
void Delay (uint32_t nTime);
uint16_t ADC1ConvertedValue = 0;
uint16_t ADC1ConvertedVoltage = 0;
int calibration_value = 0;
volatile uint32_t TimingDelay = 0;
int x =0;
int 	CoreClock = 0;
 
void SysTick_Handler(void)
{
 TimingDelay--;
}
void Delay (uint32_t nTime)
{
 TimingDelay = nTime;
 while (TimingDelay !=0);
}
 
int init ()
{
	
	//---------------------- RCC Clock Initalization ------------------------------------------------------------------
	
	RCC->CR = 0x1; //HSI on
	while((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY); // Waiting for HSI to be ready
	RCC->CR &= ~RCC_CR_PLLON; // Disable PLL
	while((RCC->CR & RCC_CR_PLLRDY)== RCC_CR_PLLRDY); // Wait for pll to turn off
	RCC->CFGR = RCC_CFGR_PLLSRC_HSI_DIV2 | RCC_CFGR_PLLMUL16 |  RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE1_DIV2; //PLLSCR = HSI/2 , PLLMUL = x16 (64Mhz),AHB prescaler not devided, APB1 Clock /2  = 32MHz (Max=32MHz)
	RCC->CR |= 0x01000000; // Turn on PLL on
	while((RCC->CR & RCC_CR_PLLRDY) != RCC_CR_PLLRDY); // Waiting for PLL to be ready
	FLASH->ACR |= FLASH_ACR_LATENCY_1; // Adjust flash speed for new frequency
	RCC->CFGR |= RCC_CFGR_SW_1; // Set PLL as system clock
	while((RCC->CFGR & RCC_CFGR_SWS_1) != RCC_CFGR_SWS_1); // Wait fpr pll to be used as syste, clock
	
	
	//---------------------- DMA Initialization -------------------------------------------------------------------
	
	RCC->AHBENR |= RCC_AHBENR_DMA1EN; // DMA1 Enabled 
	
	//---------------------- Blinky Initialization ----------------------------------------------------------------
	
	RCC->AHBENR |= (1<<18); //Enabling AHB GPIOB
	 
  GPIOB->MODER |= 0x00000010; // PB2 Output
	GPIOB->OSPEEDR |= 0x0; // Low speed output on all of port B
  GPIOB->PUPDR |= 0x30; // PB2 pull down
 
	
	//----------------------- Checking System Clock ---------------------------------------------------------------
  SystemCoreClockUpdate(); // Calculating new system clock
	CoreClock = SystemCoreClock; 
	
	while (CoreClock != 64000000) // Error Handling
	{
		GPIOB->BSRR = (1<<2) ;
	}
	
	//--------------------------- ADC Configuration ----------------------------------------------------------------
	// ADC running off sysclock at 64Mhz, with mininum cycles for conversion to ensure maximum speed
	
	
	ADC1_COMMON->CCR = 0x0; // Resetting CKMODE
	RCC->CFGR2 = RCC_CFGR2_ADC1PRES_DIV12; // ADC Prescaler /1 i.e. ADC Clock = 64Mhz
	RCC->AHBENR |= RCC_AHBENR_ADC1EN; // Enable ADC1 clock
  ADC1_COMMON->CCR = 0x0; // Resetting CKMODE
	GPIOB->MODER |=	0x0000000F; // GPIOB PB1 set to Analog Mode ADC1_IN12, ADC1_IN11
	
  // Calibration procedure 
  ADC1->CR &= ~ADC_CR_ADVREGEN;
  ADC1->CR |= ADC_CR_ADVREGEN_0; // ADC Voltage regulator enabled
  for(x=0;x<500;x++); // Delay for ADC to stabilize
	
  ADC1->CR &= ~ADC_CR_ADCALDIF; // calibration in Single-ended inputs Mode.
  ADC1->CR |= ADC_CR_ADCAL; // Start ADC calibration
  // Read at 1 means that a calibration in progress.
  while (ADC1->CR == (ADC1->CR & ADC_CR_ADCAL)); // wait until calibration done
	calibration_value = ADC1->CALFACT; // Get Calibration Value ADC1
 
 
  ADC1->CR |= ADC_CR_ADEN; // Enable ADC1
  while(!ADC1->ISR & ADC_ISR_ADRD); // wait for ADRDY
	
  ADC1->SQR1 = 0xB301; // Channel 12 first, Channel 11 second, two in sequence 
	ADC1->SMPR2 = 0x0; // Channel 11 and 12 Minimum conversion time
	ADC1->CFGR = ADC_CFGR_DMAEN | ADC_CFGR_DMACFG | ADC_CFGR_CONT; // ADC DMA Enableed and set to circular mode and ADC in continous mode
	
	DMA1_Channel1->CPAR = (uint32_t)(&(ADC1->DR)); // Passing the pheripheral address of the data register into DMA Channel 1 
  DMA1_Channel1->CMAR = (uint32_t)ADC_Samples; // Passing the address of the arry to store the data in 
	DMA1_Channel1->CNDTR = 2; // " sets of data being passed
	DMA1_Channel1->CCR |= DMA_CCR_CIRC | DMA_CCR_MINC | DMA_CCR_PSIZE_0 | DMA_CCR_MSIZE_0; // Channel 1 Circular Mode, Memory Increment , P size = 16bit, M size = 16 bit
	DMA1_Channel1->CCR |= DMA_CCR_EN; // Enabling DMA
	
  ADC1->CR |= ADC_CR_ADSTART; // Start ADC1 Software Conversion 
	
	
	//------------------------------------ UART Enable -------------------------------------
	
	RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // Enabling USART2 Clock
	RCC->AHBENR |= RCC_AHBENR_GPIOAEN;    // Enabling Port A
	
	GPIOA->MODER |= GPIO_MODER_MODER2_1 | GPIO_MODER_MODER3_1;  // Setting P24, PA3 as alternate function mode
	GPIOA->AFR[0] = 0x7700; // Alternate Functions USART 2 For PA2, PA3
 
	
  
	USART2->BRR = 0xD05; // 32MHz / 9600
	USART2->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE | USART_CR1_TXEIE; // Transmit Enable, Revive Enable, RX not empty Int Enable, TX not empty Int Enable
	USART2->CR1 |=  USART_CR1_UE; // Uart Enable 
	
	NVIC_EnableIRQ(USART2_IRQn); // Enabling USART2 interrupt
	
	return(0);
	
}
int main()
{
 
	init();
 
	while (1)
	{
		
		GPIOB->BSRR = (1<<2) ;
		for ( x = 0; x<5000; x++)
		{
		}
		GPIOB->BSRR = (1<<(2+16));
		for ( x = 0; x<5000; x++)
		{
		}
	
	
}
}
 
	
void USART2_IRQHandler(void)
{
		if (USART2->ISR & USART_ISR_RXNE)
		{
			char temp =  USART2->RDR;
			USART2->TDR = temp;
			while(!(USART2->ISR & USART_ISR_TC));
		}
		
		if (USART2->ISR & USART_ISR_TXE)
		{
		
		}
			
}

Do you guys have any ideas on might have cause this?

Thanks,

Glenn

5 REPLIES 5

Don't enable the TXE interrupt unless you have data ready to send.

Don't spin on status in the IRQ handler.

Check for noise and framing type errors on the USART and clear them if observed.​

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

HI Clive,

What do you mean by don't spin on the status of the IRQ handler? I don't get the context.

I have disabled the transmit interrupt as it makes sense as you pointed out, as when I was sending the character the interrupt would be called again. So that helped me a lot.

However I am still having the issue of getting incorrect characters sent back . I am trying to work on this issue. I know that all my clocks are within spec and the baud rate is set correctly. I had an earlier version of the code were I would "poll" the uart and changing the KEil compiler from level 0 to default solved that however when I do that with the UART in interrupt mode the code doesn't work in default mode. I am trying to fix it as we speak, hopefully I will figure it out.

Many thanks for your help0690X000008BYuxQAG.png

while(!(USART2->ISR & USART_ISR_TC)); // Don't do this, it is time consuming and pointless

void USART2_IRQHandler(void) // Minimal IRQ handler for echo

{

 if (USART2->ISR & USART_ISR_RXNE)

  USART2->TDR = USART2->RDR & 0xFF;

 // would recommend checking/clearing PE, FE, NE type input errors here

}

while(1) // Equivalent polled operation, test first before using interrupts

{

 if (USART2->ISR & USART_ISR_RXNE)

 {

  char temp = USART2->RDR;

  USART2->TDR = temp;

 }

}

The USART does not accept RS232 levels, expects CMOS/TTL levels. Not clear how this echo back loop is actually implemented.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..

I have tried your recommendations but alas still have the issue. I don't think its noise as its either one of two characters not just random ones. Furthermore, I set the baud rate so there is no remainder when it is divided to fit into the BRR register also to no avail.

The offset between the two characters that I receive seems to 128 decimal which is undefined in the ASCII table. I am at a bit of a loss now

I have taken a look at the ISR register and the noise flag is being set with every transmission. I have been clearing the flag when it is set. However it is set every time regardless of whether the correct character has been sent or not

void USART2_IRQHandler(void)
{
	  if((USART2->ISR & USART_ISR_RXNE) == USART_ISR_RXNE)
		{
			 USART2->TDR = USART2->RDR & 0xFF;
			 if ((USART2->ISR & USART_ISR_NE) == USART_ISR_NE)
			 {
			 USART2->ICR = USART_ICR_NCF;
			 }
		}
		
}