2019-05-12 04:07 AM
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
2019-05-12 05:12 AM
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.
2019-05-12 05:53 AM
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 help
2019-05-12 09:34 AM
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.
2019-05-12 10:39 AM
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
2019-05-12 11:01 AM
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;
}
}
}