Skip to main content
glenn0010
Associate III
May 12, 2019
Question

Erratic USART behaviour using KEIL 5 Compiler

  • May 12, 2019
  • 1 reply
  • 1411 views

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

This topic has been closed for replies.

1 reply

Tesla DeLorean
Guru
May 12, 2019

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 VenmoUp vote any posts that you find helpful, it shows what's working..
glenn0010
glenn0010Author
Associate III
May 12, 2019

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

Tesla DeLorean
Guru
May 12, 2019

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 VenmoUp vote any posts that you find helpful, it shows what's working..