Embedded software program block, I2C? - c

I have experienced a very strange problem in developing my application for the ST Microelectronics iNemo. My applications consists in:
Gyroscope reading with SPI
Accelerometer and Magnetometer (in the same device) reading with I2C
Attitude estimation algorithm
PD functions
Data receiving with USART, with interrupt without DMA
Sending of logging packet, with USART
The loop is triggered by a timer at 100Hz.
The program works well (I have tested it with some USART debug prints) until I start sending data with the USART: my initial guess was that, since this fact enables the receiving of interrupts, it causes problem with the I2C bus arbitrage mechanism. My guess is derived that when I have succeeded in debugging the problem (that is time dependent), with USART prints, I have detected that the last print is always before the accelerometer of magnetometer prints (the first that I call in my code).
Additionally, If I enable the verbose debug prints via USART that I have mentioned the problem occurs in fewer occasions, while if I disable it and I send only logging packet the problem occurs always and immediately. Anyone can give me an idea of what can be the cause of this problem? Thanks
EDIT: I attach my I2C code:
#define DMA_BUFFER_SIZE 196
#define FORCE_CRITICAL_SEC
/**
* #brief DMA initialization structure variable definition.
*/
DMA_InitTypeDef I2CDMA_InitStructure;
/**
* #brief Volatile variable definition for I2C direction.
*/
__IO uint32_t I2CDirection = I2C_DIRECTION_TX;
void iNemoI2CInit(I2C_TypeDef* I2Cx, uint32_t I2CxSpeed)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIO clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
/* Configure I2C pins: SCL and SDA */
if(I2Cx==I2C2)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
}
else
{
GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
}
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x00;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = I2CxSpeed;
/* Apply I2C configuration after enabling it */
I2C_Init(I2Cx, &I2C_InitStructure);
/* I2C Peripheral Enable */
I2C_Cmd(I2Cx, ENABLE);
/* Enable DMA if required */
#if (defined(I2C1_USE_DMA_TX) || defined(I2C1_USE_DMA_RX))
if (I2Cx==I2C1)
iNemoI2CDMAInit(I2C1);
#endif
#if (defined(I2C2_USE_DMA_TX) || defined(I2C2_USE_DMA_RX))
if (I2Cx==I2C2)
iNemoI2CDMAInit(I2C2);
#endif
}
void iNemoI2CDMAInit(I2C_TypeDef* I2Cx)
{
/* Enable the DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* I2C TX DMA Channel configuration */
I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)0; /* This parameter will be configured durig communication */
I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; /* This parameter will be configured durig communication */
I2CDMA_InitStructure.DMA_BufferSize = 0xFFFF; /* This parameter will be configured durig communication */
I2CDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
I2CDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
I2CDMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
I2CDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
I2CDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
I2CDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
I2CDMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
if(I2Cx==I2C2)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
#ifdef I2C2_USE_DMA_TX
DMA_DeInit(I2C2_DMA_CHANNEL_TX);
DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
#endif
#ifdef I2C2_USE_DMA_RX
/* I2C2 RX DMA Channel configuration */
DMA_DeInit(I2C2_DMA_CHANNEL_RX);
DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
#endif
}
if(I2Cx==I2C1)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
#ifdef I2C1_USE_DMA_TX
DMA_DeInit(I2C1_DMA_CHANNEL_TX);
DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
#endif
#ifdef I2C1_USE_DMA_RX
/* I2C1 RX DMA Channel configuration */
DMA_DeInit(I2C1_DMA_CHANNEL_RX);
DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
#endif
}
void iNemoI2CDMAConfig(I2C_TypeDef* I2Cx, uint8_t* pBuffer, uint32_t lBufferSize, uint32_t lDirection)
{
/* Initialize the DMA with the new parameters */
if (lDirection == I2C_DIRECTION_TX)
{
/* Configure the DMA Tx Channel with the buffer address and the buffer size */
I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)lBufferSize;
if(I2Cx==I2C2)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
DMA_Init(I2C2_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
DMA_Cmd(I2C2_DMA_CHANNEL_TX, ENABLE);
}
else
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE);
DMA_Init(I2C1_DMA_CHANNEL_TX, &I2CDMA_InitStructure);
DMA_Cmd(I2C1_DMA_CHANNEL_TX, ENABLE);
}
}
else /* Reception */
{
/* Configure the DMA Rx Channel with the buffer address and the buffer size */
I2CDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)pBuffer;
I2CDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
I2CDMA_InitStructure.DMA_BufferSize = (uint32_t)lBufferSize;
if(I2Cx==I2C2)
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C2_DR_Address;
DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
DMA_Init(I2C2_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
DMA_Cmd(I2C2_DMA_CHANNEL_RX, ENABLE);
}
else
{
I2CDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)I2C1_DR_Address;
DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE);
DMA_Init(I2C1_DMA_CHANNEL_RX, &I2CDMA_InitStructure);
DMA_Cmd(I2C1_DMA_CHANNEL_RX, ENABLE);
}
}
}
void iNemoI2CBufferReadDma(I2C_TypeDef* I2Cx, uint8_t cAddr, uint8_t* pcBuffer, uint8_t cReadAddr, uint8_t cNumByteToRead)
{
__IO uint32_t temp = 0;
__IO uint32_t Timeout = 0;
/* Enable I2C errors interrupts */
I2Cx->CR2 |= I2C_IT_ERR;
/* Set the MSb of the register address in case of multiple readings */
if(cNumByteToRead>1)
cReadAddr |= 0x80;
#ifdef FORCE_CRITICAL_SEC
__disable_irq();
#endif
#ifdef USART_DEBUG2
USART1_Printf("FLAG BUSY\r\n");
#endif
Timeout = 0xFFFF;
/* While the bus is busy */
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY)){
if (Timeout-- == 0)
return;
}
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
#ifdef USART_DEBUG2
USART1_Printf("MASTER MODE\r\n");
#endif
Timeout = 0xFFFF;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){
if (Timeout-- == 0)
return;
}
/* Send LSM303DLH address for read */
I2C_Send7bitAddress(I2Cx, cAddr, I2C_Direction_Transmitter);
Timeout = 0xFFFF;
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){
if (Timeout-- == 0)
return;
}
/* Clear EV6 by setting again the PE bit */
I2C_Cmd(I2Cx, ENABLE);
/* Send the LSM303DLH_Magn's internal address to write to */
I2C_SendData(I2Cx, cReadAddr);
#ifdef USART_DEBUG2
USART1_Printf("BYTE TRANSMITTED\r\n");
#endif
Timeout = 0xFFFF;
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){
if (Timeout-- == 0)
return;
}
/* Configure I2Cx DMA channel */
iNemoI2CDMAConfig(I2Cx, pcBuffer, cNumByteToRead, I2C_DIRECTION_RX);
/* Set Last bit to have a NACK on the last received byte */
I2Cx->CR2 |= 0x1000;
/* Enable I2C DMA requests */
I2C_DMACmd(I2Cx, ENABLE);
Timeout = 0xFFFF;
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
Timeout = 0xFFFF;
/* Wait until SB flag is set: EV5 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if (Timeout-- == 0)
return;
}
Timeout = 0xFFFF;
/* Send LSM303DLH address for read */
I2C_Send7bitAddress(I2Cx, cAddr, I2C_Direction_Receiver);
Timeout = 0xFFFF;
/* Wait until ADDR is set: EV6 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if (Timeout-- == 0)
return;
}
/* Clear ADDR flag by reading SR2 register */
temp = I2Cx->SR2;
if(I2Cx == I2C2)
{
Timeout = 0xFFFF;
/* Wait until DMA end of transfer */
while (!DMA_GetFlagStatus(DMA1_FLAG_TC5)){
if (Timeout-- == 0)
return;
}
/* Disable DMA Channel */
DMA_Cmd(I2C2_DMA_CHANNEL_RX, DISABLE);
/* Clear the DMA Transfer Complete flag */
DMA_ClearFlag(DMA1_FLAG_TC5);
}
else
{
/* Wait until DMA end of transfer */
#ifdef USART_DEBUG2
USART1_Printf("END TRANSFER\r\n");
#endif
Timeout = 0xFFFF;
while (!DMA_GetFlagStatus(DMA1_FLAG_TC7)){
if (Timeout-- == 0)
return;
}
/* Disable DMA Channel */
DMA_Cmd(I2C1_DMA_CHANNEL_RX, DISABLE);
/* Clear the DMA Transfer Complete flag */
DMA_ClearFlag(DMA1_FLAG_TC7);
}
/* Disable Ack for the last byte */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
#ifdef USART_DEBUG2
USART1_Printf("STOP BIT\r\n");
#endif
Timeout = 0xFFFF;
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
while ((I2Cx->CR1 & 0x0200) == 0x0200){
if (Timeout-- == 0)
return;
}
/* Enable Acknowledgement to be ready for another reception */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
#ifdef FORCE_CRITICAL_SEC
__enable_irq();
#endif
}
void iNemoI2CBufferWriteDma(I2C_TypeDef* I2Cx, uint8_t cAddr, uint8_t* pcBuffer, uint8_t cWriteAddr, uint8_t cNumByteToWrite)
{
__IO uint32_t temp = 0;
__IO uint32_t Timeout = 0;
static uint8_t pcDmaBuffer[DMA_BUFFER_SIZE+1];
/* Set to 1 the MSb of the register address in case of multiple byte writing */
if(cNumByteToWrite>1)
cWriteAddr |= 0x80;
pcDmaBuffer[0]=cWriteAddr;
memcpy(&pcDmaBuffer[1],pcBuffer,cNumByteToWrite);
/* Enable Error IT */
I2Cx->CR2 |= I2C_IT_ERR;
Timeout = 0xFFFF;
/* Configure the DMA channel for I2Cx transmission */
iNemoI2CDMAConfig(I2Cx, pcDmaBuffer, cNumByteToWrite+1, I2C_DIRECTION_TX);
/* Enable DMA for I2C */
I2C_DMACmd(I2Cx, ENABLE);
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Wait until SB flag is set: EV5 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
{
if (Timeout-- == 0)
return;
}
Timeout = 0xFFFF;
/* Send LSM303DLH address for write */
I2C_Send7bitAddress(I2Cx, cAddr, I2C_Direction_Transmitter);
/* Wait until ADDR is set: EV6 */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (Timeout-- == 0)
return;
}
/* Clear ADDR flag by reading SR2 register */
temp = I2Cx->SR2;
/* Disable the DMA1 channel */
if(I2Cx == I2C2)
{
/* Wait until DMA end of transfer */
while (!DMA_GetFlagStatus(DMA1_FLAG_TC4));
/* Disable DMA Channel */
DMA_Cmd(I2C2_DMA_CHANNEL_TX, DISABLE);
/* Clear the DMA Transfer complete flag */
DMA_ClearFlag(DMA1_FLAG_TC4);
}
else
{
/* Wait until DMA end of transfer */
while (!DMA_GetFlagStatus(DMA1_FLAG_TC6));
/* Disable DMA Channel */
DMA_Cmd(I2C1_DMA_CHANNEL_TX, DISABLE);
/* Clear the DMA Transfer complete flag */
DMA_ClearFlag(DMA1_FLAG_TC6);
}
/* EV8_2: Wait until BTF is set before programming the STOP */
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Make sure that the STOP bit is cleared by Hardware before CR1 write access */
while ((I2Cx->CR1 & 0x0200) == 0x0200);
}

I see that for some while loops you have a timeout, but for some you don't:
while ((I2Cx->CR1 & 0x0200) == 0x0200);
Make all your loops timeout, and also make a note where the error condition occurs (it needs to be investigated - if you don't know the reason, it will come back to haunt you later).
Hardware can be a bit buggy at times, so it completely possible you're doing everything correctly, but it still doesn't work. Check errata (for STM32 I2C and your I2C slaves) for documented bugs.
A few years ago I came across an issue where I2C lines would stay low, and I had to reconfigure pins as GPIO, bit-bang some bits out, and then it I could switch back to I2C operation.

Related

Why wouldn't my HAL_UART IT capture callback routine trigger?

I'm trying to establish communication between two STM32F103 MCU's via UART. I'm using STMCubeMX to build peripheral initalization. I've logicaly named the MCU's as MASTER and SLAVE. Slave UART is configured as Transmit only, while MASTER uart is recieve only. I'm using HAL drivers to program the MCU in AtollicTRUEstudio IDE. I want to send uint32_t value, buffer_USART1_rx is declared as volatile uint8_t buffer_USART1_rx[10]. Basicly SLAVE UART transmit is being triggered by Systick timer every 1 second, while MASTER UART is defined in IT mode, and soon as the interrupt happens it read the transmited value.
I connected the osciloscope probe to the PA10 RX pin of MASTER and i noticed the UART signal is fine and transmiting over the wires. But the value being transmitted is always 0 and breakpoint in HAL_UART_RxCpltCallback is never activated. Since the osciloscope signal is correct, i'm thinking it's a software issue.
Image of RX PA10 pin of MASTER stm32
This is from MASTER STM (code is located in main file)
UART initialization:
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
static void MX_NVIC_Init(void)
{
/* USART1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
__NOP();
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/*UART1 water level from SLAVE */
if(huart->Instance==USART1)
{
water_level=getUSART1();
/* Water level change triggers LCD refresh */
if(water_level_prev!=water_level)
{
lcd_screen_refresh=true;
}
water_level_prev=water_level;
}
else
{
__NOP();
}
/*UART2 target level from NANOPI */
if(huart->Instance==USART2)
{
target_level_pi=getUSART2();
/* Target level change triggers LCD refresh */
if(target_level_pi!=target_level_prev)
{
lcd_screen_refresh=true;
}
}
else
{
__NOP();
}
}
UART deserialize function:
uint32_t getUSART1()
{
uint32_t num=0;
num |= buffer_USART1_rx[0] << 24;
num |= buffer_USART1_rx[1] << 16;
num |= buffer_USART1_rx[2] << 8;
num |= buffer_USART1_rx[3];
return num;
}
In main file initialization of UART in IT mode:
/* Initialize TIM/UART interrupts */
HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_2);
HAL_UART_Receive_IT(&huart1, buffer_USART1_rx, 4);
SLAVE MCU configuration :
// This is in while loop
if(send_USART==true)
{
buffer[0] = test ;
buffer[1] = test >>8;
buffer[2] = test >> 16;
buffer[3] = test >> 24;
HAL_UART_Transmit(&huart1,buffer,4,2000);
}
else
{
__NOP();
}
// Callback
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
send_USART=false;
}
//Systick timer triggers UART transmit every 1 second
void HAL_SYSTICK_Callback()
{
sys_timer++;
if(sys_timer>=1000)
{
sys_timer=0;
send_USART=true;
}
else
{
__NOP();
}
}
//Global declaration of variables used
/* Timer variables */
uint8_t buffer[10];
volatile uint32_t sys_timer=0;
uint32_t test=10;
/* Boolean variables */
bool send_USART=false;
// UART initialization
/* USART1 init function */
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
static void MX_NVIC_Init(void)
{
/* USART1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(USART1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
I expect the recieved value to be 10. (since i'm serializing "test" variable on SLAVE stm, and sending it on MASTER stm while deserializing it)
Nevermind, i've found the issue and what was causing it
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
if(huart1.RxState==HAL_UART_STATE_READY)
{
HAL_UART_Receive_IT(&huart1,buffer_USART1_rx,4);
uart1_received=4; //flag da je primljen podatak
__HAL_UART_FLUSH_DRREGISTER(&huart1);
__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
}
else
{
__NOP();
}
/* USER CODE END USART1_IRQn 1 */
}
The code for handling was above the HAL_UART_IRQHandler(&huart1); . That's why it only recieved data once. When I copied it below like on the code above, everything works fine.

stm32f103: Force DMA transfer complete interrupt

I'm trying to implement communication between stm32f103 and SIM900A using FreeRTOS (mutexes and stream buffers), DMA and USART3.
I've enabled USART_IT_IDLE USART3 interrupt to be able to detect end of SIM900 transmittion and make force firing of DMA transmission complete interrupt to copy data from memory into FreeRtos's streamBuffer.
This article said that this is possible.
/**
* \brief Global interrupt handler for USART2
*/
void USART2_IRQHandler(void) {
/* Check for IDLE flag */
if (USART2->SR & USART_FLAG_IDLE) { /* We want IDLE flag only */
/* This part is important */
/* Clear IDLE flag by reading status register first */
/* And follow by reading data register */
volatile uint32_t tmp; /* Must be volatile to prevent optimizations */
tmp = USART2->SR; /* Read status register */
tmp = USART2->DR; /* Read data register */
(void)tmp; /* Prevent compiler warnings */
DMA1_Stream5->CR &= ~DMA_SxCR_EN; /* Disabling DMA will force transfer complete interrupt if enabled */
}
}
But my debugger says: no
Here is my code:
#define BUFF_SIZE 16
uint8_t RX_BUFFER[BUFF_SIZE] = {"\0"};
uint8_t TX_BUFFER[BUFF_SIZE] = {"\0"};
....
// USART TX channel
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->DR);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&TX_BUFFER[0];
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStruct.DMA_BufferSize = sizeof(TX_BUFFER);
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel2, &DMA_InitStruct);
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&RX_BUFFER[0];
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = sizeof(RX_BUFFER);
DMA_Init(DMA1_Channel3, &DMA_InitStruct);
// USART RX channel
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&RX_BUFFER[0];
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = sizeof(RX_BUFFER);
DMA_Init(DMA1_Channel3, &DMA_InitStruct);
// Interrupts
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);
USART_DMACmd(USART3, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
USART_Cmd(USART3, ENABLE);
DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel3, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY + 10;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_Init(&NVIC_InitStructure);
....
void USART3_IRQHandler() {
if (USART_GetITStatus(USART3, USART_IT_IDLE) == SET) {
volatile uint32_t tmp = USART3->SR;
tmp = USART3->DR;
(void) tmp;
// HERE interrupt should be fired!
DMA1_Channel3->CCR &= (uint16_t)(~DMA_CCR1_EN);
USART_ClearITPendingBit(USART3, USART_IT_IDLE);
}
}
void DMA1_Channel3_IRQHandler(void) {
if (DMA_GetITStatus(DMA1_IT_TC3) == SET) {
uint8_t len = BUFF_SIZE - DMA1_Channel3->CNDTR;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xStreamBufferSendFromISR(xUSART3ReceiveStreamBuffer, &RX_BUFFER, len, &xHigherPriorityTaskWoken);
for (uint8_t i = 0; i < len; i++) {
RX_BUFFER[i] = '\0';
}
DMA1_Channel3->CNDTR = BUFF_SIZE;
DMA_Cmd(DMA1_Channel3, ENABLE);
DMA_ClearITPendingBit(DMA1_IT_TC3);
}
}
Why I can't force DMA1_IT_TC3 interrupt? Or can it be forced on STM32F103?

smt32 interrupts. why my diode is not blinking?

I have smt32l1xx board and this code below is not working. Debugger shows pinA5 is set, but diode connected to this pin is still not lightening. I dont know why. Even i add delay after setting bit it is not working. diode is connected to PA5 and GND on board.
#include <stm32l1xx.h>
#define ENABLE 1
#define DISABLE 0
void TIM2_IRQHandler() //interrupt
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5))
GPIO_ResetBits(GPIOA, GPIO_Pin_5); //LED OFF
else
GPIO_SetBits(GPIOA, GPIO_Pin_5); //LED ON <- im here and still nothing
}
}
int main(void)
{
/* gpio init struct */
GPIO_InitTypeDef gpio;
TIM_TimeBaseInitTypeDef tim;
NVIC_InitTypeDef nvic;
/* reset rcc */
RCC_DeInit();
RCC_APB2PeriphClockCmd(RCC_AHBENR_GPIOAEN, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
GPIO_StructInit(&gpio);
/* use pin 0 */
gpio.GPIO_Pin = GPIO_Pin_5;
/* mode: output */
gpio.GPIO_Mode = GPIO_Mode_OUT;
/* apply configuration */
GPIO_Init(GPIOA, &gpio);
TIM_TimeBaseStructInit(&tim); //timer
tim.TIM_CounterMode = TIM_CounterMode_Up;
tim.TIM_Prescaler = 64000 - 1;
tim.TIM_Period = 1000 - 1;
TIM_TimeBaseInit(TIM2, &tim);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);
nvic.NVIC_IRQChannel = TIM2_IRQn; //interrupt
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
while (1)
{
}
/* never reached */
return 0;
}
To make sure that your hardware is properly initialized, you should use STM32CubeMX.
It seems that the GPIOA clock is on the AHB bus, however you call RCC_APB2PeriphClockCmd which is for APB2. So try to use the equivalent for AHB something like RCC_AHBPeriphClockCmd

STM32F3 UART receive interrupt data hangs after receveing first set of data from Arduino

Being beginner in ARM microcontroller, I am using STM32F3 Discovery Kit to communicate with Arduino. I use EWARM for coding and Putty, for serial terminal.
I did an echo test on stm32f3 UART2. The data is displayed on the serial terminal correctly, so I confirmed the uart communication is working as expected.
Then, I try to transfer data from arduino to stm32f3 but the uart on stm32f3 hangs after the first set of data (the first set of data is displayed with correctly with some garbage character included). I have been stuck for quite some time now.
Below is the coding I used for UART. The baudrate is 9600. Can anyone help?
#define LINEMAX 15 // Maximal allowed/expected line length
volatile char line_buffer[LINEMAX + 1]; // Holding buffer with space for terminating NUL
volatile int line_valid = 0;
/**
* #brief Initialize USART2 for PD6 (USART2_RX) and PD5 (USART2_TX)
* used for receiving mouse data from arduino
* #param baudrate; by default is 9600
* #retval None
* link: http://eliaselectronics.com/stm32f4-usart-example-with-interrupt/
*/
void init_USART2(int baudrate)
{
USART_InitTypeDef USART_InitStructure; // this is for the GPIO pins used as TX and R
GPIO_InitTypeDef GPIO_InitStructure; // this is for the USART1 initilization
NVIC_InitTypeDef NVIC_InitStructure; // this is used to configure the NVIC (nested vector interrupt controller)
/* Configure USART1 pins: Rx and Tx ----------------------------*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_7);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_7);
/* Configure USART1 pins: --------------------------------------*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
USART_DeInit(USART2);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2,&USART_InitStructure);
USART_Cmd(USART2, ENABLE);
/* Here the USART2 receive interrupt is enabled
* and the interrupt controller is configured
* to jump to the USART2_IRQHandler() function
* if the USART2 receive interrupt occurs
*/
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // enable the USART2 receive interrupt
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; // we want to configure the USART1 interrupts
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // this sets the priority group of the USART1 interrupts
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // this sets the subpriority inside the group
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // the USART2 interrupts are globally enabled
NVIC_Init(&NVIC_InitStructure); // the properties are passed to the NVIC_Init function which takes care of the low level stuff
// finally this enables the complete USART2 peripheral
USART_Cmd(USART2, ENABLE);
}
void serial_prints (USART_TypeDef* USARTx, volatile char *buffer)
{
/* transmit till NULL character is encountered */
while(*buffer)
{
USART_SendData(USARTx, *buffer++);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
delay_us(5);
}
}
void USART2_IRQHandler(void)
{
static char rx_buffer[LINEMAX]; // Local holding buffer to build line
static int rx_index = 0;
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) // Received character?
{
char rx = USART_ReceiveData(USART2);
if ((rx == '\r') || (rx == '\n')) // Is this an end-of-line condition, either will suffice?
{
if (rx_index != 0) // Line has some content?
{
memcpy((void *)line_buffer, rx_buffer, rx_index); // Copy to static line buffer from dynamic receive buffer
line_buffer[rx_index] = 0; // Add terminating NUL
line_valid = 1; // flag new line valid for processing
serial_prints(USART2, rx_buffer);
rx_index = 0; // Reset content pointer
}
}
else
{
if (rx_index == LINEMAX) // If overflows pull back to start
rx_index = 0;
rx_buffer[rx_index++] = rx; // Copy to buffer and increment
}
}
}
For arduino, I use the following code and the data is displayed correctly in the serial terminal:
printf("%d, %d \n", X, Y);
You add the terminating null character to line_buffer, but then you pass rx_buffer to the function serial_prints:
line_buffer[rx_index] = 0; // Add terminating NUL
line_valid = 1; // flag new line valid for processing
serial_prints(USART2, rx_buffer);
rx_index = 0; // Reset content pointer
This has the consequence that you will iterate past the length of buffer in the function serial_prints because buffer will not be null terminated:
while(*buffer)
{
USART_SendData(USARTx, *buffer++);
while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET);
delay_us(5);
}
On a side-node, you should also use interrupts to send your characters (TX Empty interrupts). Actively waiting in the interrupt service routine for UART characters to be sent will considerably slow-down your program.

USART communication with a STM32f1xx

I try to achieve an USART communication. So I connect the RX of my STM32f1 with his TX.
Also I write a program for this communication. This code is composed of the following components:
RCC configuration
GPIO configuration
USART configuration
Send and receive of a string
Comparison between the sent string and the received string
Test if the communication succeeded => LED4 turn on else the LED3 turn on
The problem is in all cases the LED3 turns on. It means that the data transmission failed.
With my IDE (IAR's Embedded Workbench) I compile this program code:
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32_eval.h"
/* Private typedef -----------------------------------------------------------*/
typedef enum { FAILED = 0, PASSED = !FAILED} TestStatus;
/* Private define ------------------------------------------------------------*/
#define USARTy USART1
#define USARTy_GPIO GPIOA /* PORT name*/
#define USARTy_CLK RCC_APB2Periph_USART1
#define USARTy_GPIO_CLK RCC_APB2Periph_GPIOA
#define USARTy_RxPin GPIO_Pin_10/* pin Rx name*/
#define USARTy_TxPin GPIO_Pin_9 /* pin Tx name*/
#define USARTz USART2
#define USARTz_GPIO GPIOA/* PORT name*/
#define USARTz_CLK RCC_APB1Periph_USART2
#define USARTz_GPIO_CLK RCC_APB2Periph_GPIOA
#define USARTz_RxPin GPIO_Pin_3/* pin Rx name*/
#define USARTz_TxPin GPIO_Pin_2/* pin Tx name*/
#define TxBufferSize (countof(TxBuffer))
/* Private macro -------------------------------------------------------------*/
#define countof(a) (sizeof(a) / sizeof(*(a)))
/* Private variables ---------------------------------------------------------*/
USART_InitTypeDef USART_InitStructure;
uint8_t TxBuffer[] = "Bufferrr";
uint8_t RxBuffer[8];
__IO uint8_t TxConteur = 0, RxConteur = 0;
volatile TestStatus TransferStatus = FAILED;
/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
__IO uint8_t index = 0;
GPIO_InitTypeDef GPIO_InitStructure;
int main(void)
{
STM_EVAL_LEDInit(LED1);
STM_EVAL_LEDInit(LED2);
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* System Clocks Configuration */
RCC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
USART_InitStructure.USART_BaudRate = 230400 /*115200*/;
USART_InitStructure.USART_WordLength =USART_WordLength_8b ;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
/* Configure USARTy */
USART_Init(USART1,&USART_InitStructure);
/* Enable the USARTy */
USART_Cmd(USART1,ENABLE);
while(TxConteur < TxBufferSize)
{
/* Send one byte from USARTy to USARTz */
USART_SendData(USARTy, TxBuffer[TxConteur++]);
/* Loop until USARTy DR register is empty */
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
{
}
/* Store the received byte in RxBuffer */
RxBuffer[RxConteur++] = USART_ReceiveData(USARTy) & 0xFF;
}
/* Check the received data with the send ones */
TransferStatus = Buffercmp(TxBuffer, RxBuffer, TxBufferSize);
/* TransferStatus = FAILED, if the data transmitted from USARTy and
received by USARTz are different */
if (TransferStatus == FAILED)
{
STM_EVAL_LEDOn(LED3);
}
else
{
STM_EVAL_LEDOn(LED4);
}
while (1)
{
}
}
void RCC_Configuration(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure1,GPIO_InitStructure2;
/* Configure USARTy Rx as input floating */
GPIO_InitStructure1.GPIO_Pin =GPIO_Pin_10;
GPIO_InitStructure1.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure1);
/* Configure USARTy Tx as alternate function push-pull */
GPIO_InitStructure2.GPIO_Pin =GPIO_Pin_9;
GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure2);
/* Configure USARTz Tx as alternate function push-pull */
}
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while(BufferLength--)
{
if(*pBuffer1 != *pBuffer2)
{
return FAILED;
}
pBuffer1++;
pBuffer2++;
}
return PASSED;
}
Like explained in a comment by Hans Passant, the OP was testing the flag USART_FLAG_TC (Transmission Completed) instead of the flag USART_FLAG_RXNE (RX buffer Not Empty).

Resources