CubeMX - I2C DMA - help needed - ST32F1 - i2c

HAL_I2C_Mem_Write_DMA / HAL_I2C_Mem_Read_DMA what is the problem ?
Hi I'm trying to run I2C in DMA mode with LIS35 (accelerometer). I wrote simple code as below but each time when I try to run or debug it I'm getting back return "LIS35_ERROR;" which means that LIS35_I2C_Init(void) function goes wrong.
Previously (I mean yesterday) I wrote two similarly projects:
First was based on HAL_I2C_Mem_Write / HAL_I2C_Mem_Read functions
- and all works properly (return LIS35_OK;)
Second was based on HAL_I2C_Mem_Write_IT / HAL_I2C_Mem_Read_IT functions
- and all works properly(return LIS35_OK;)
Environment:
STM32CubeMX - updated today,
Board - Nucleo-F103RB
CubeMX project added as attachment
I2C configuration al on pictures below
/* USER CODE BEGIN 4 */
char LIS35_I2C_Init(void)
{
uint8_t Sett_Lis35_cr2_boot = LIS35_REG_CR2_BOOT;
uint8_t RegVal, LIS35Settings;
HAL_StatusTypeDef state1, state2, state3;
volatile long int i;
//reset LIS35 settings
if(HAL_I2C_Mem_Write_DMA(&hi2c2, LIS35_Addr, LIS35_REG_CR2, 1, &Sett_Lis35_cr2_boot, 1) != HAL_OK) {
//led blink info
}
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){}
//Write settings - activate all axis
LIS35Settings = LIS35_REG_CR1_XEN | LIS35_REG_CR1_YEN | LIS35_REG_CR1_ZEN | LIS35_REG_CR1_ACTIVE;
//WRITE CONFIGURATION TO LIS35 CHIP
if(HAL_I2C_Mem_Write_DMA(&hi2c2, LIS35_Addr, LIS35_REG_CR1, 1, &LIS35Settings, 1)!= HAL_OK) {
//led blink info
}
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){}
//Read configuration - if OK, LIS35 is up and running
if(HAL_I2C_Mem_Read_DMA(&hi2c2, LIS35_Addr, LIS35_REG_CR1, 1, &RegVal, 1) != HAL_OK) {
//led blink info
}
while (HAL_I2C_GetState(&hi2c2) != HAL_I2C_STATE_READY){}
if (RegVal == LIS35Settings){
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
return LIS35_OK;
}
return LIS35_ERROR;
}
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c){
static uint8_t cntTx;
cntTx++;
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c){
static uint8_t cntRx;
cntRx++;
}
/* USER CODE END 4 */
Thanks in advance for any help :-)
Farnk

Related

STM32 HAL I2C IsDeviceReady (I2C detect) device Plug out and Plug in again - No Device found

I am implementing I2C detect feature in my stm32 ptoject, but I came across a problem. I am using stm32F103C8T6 (BluePill) and Nucloe-144 board which shows the same behavior.
The problem:
When I'm running i2cdetect function in loop with some delay (3-5 sec) I can see the address of my i2c slave device (e.g. MCP23008), but if I plug connector out (4pin connector = gnd,scl,sda,vcc at the same time) and then plug it in again I can't see the device until I reset I2C master (bluepill or nucleo).
Note: I can plug out and plug in again i2c slaves as many times as I want and I will see them every time I use the i2cdetect command from i2ctools with my raspberry pi 3 model B.
My i2cmaster code implementing i2cdetect:
int main(void)
{
while (1)
{
i2c_detect();
HAL_Delay(5000);
}
}
void i2c_detect(void)
{
char str[56]; uint8_t len=0; uint8_t devices = 0, ret;
extern I2C_HandleTypeDef hi2c1;
CDC_Transmit_FS((uint8_t*)"\r\nSearching for I2C devices on the bus...\r\n", strlen("\r\nSearching for I2C devices on the bus...\r\n"));
for (uint8_t i = 1; i < 128; i++)
{
ret = HAL_I2C_IsDeviceReady(&hi2c1, (uint8_t)(i<<1), 3, 10);
if (ret != HAL_OK) /* No ACK Received At That Address */
{
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)" - ", strlen(" - ")));
}
else if (ret == HAL_OK)
{
len=sprintf(str,"0x%X",i);
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)str, len));
devices++;
}
}
/* Feedback of the total number of devices. */
if (devices == 0)
{
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)"\r\nNo device found.", strlen("\r\nNo device found.")));
}
else
{
len=sprintf(str,"\r\nTotal found devices: %d",devices);
while (USBD_BUSY == CDC_Transmit_FS((uint8_t*)str, len));
}
}
So, any thoughts why this happening? How can I implement behavior same to i2cdetect from i2ctools on Linux?

Using DMA with two UART peripherals - is it possible?

I want to connect two UART peripherals using STM32G0 microcontroller via DMA. Not knowing the length of the messages in forward, I'm using function HAL_UARTEx_ReceiveToIdle_DMA() in order to receive them. Here is the part of my code:
main.h
.
.
.
StartDMAReceptionOverUART1();
StartDMAReceptionOverUART4();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(10);
}
.
.
.
void StartDMAReceptionOverUART1(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_modulePort.huart, m_modulePort.rxBuffer, m_modulePort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_TC);
}
void StartDMAReceptionOverUART4(void)
{
if (HAL_UARTEx_ReceiveToIdle_DMA(m_meterPort.huart, m_meterPort.rxBuffer, m_meterPort.rxBufferSize) != HAL_OK)
{
Error_Handler();
}
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_HT);
__HAL_DMA_DISABLE_IT(&hdma_usart4_rx, DMA_IT_TC);
}
.
.
.
These functions are similar: first HAL_UARTEx_ReceiveToIdle_DMA() is checked, then Half Transfer and Transfer Complete interrupts are disabled in order to relieve processor (I need only IDLE interrupt). The problem is inside StartDMAReceptionOverUART1() function, HAL_UARTEx_ReceiveToIdle_DMA() never returns HAL_OK and program jumps on Error_Handler(). On the other hand, StartDMAReceptionOverUART4() works perfectly fine. What could be the problem?
Also, here is the receive callback function, also written inside main.h:
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == m_meterPort.huart->Instance) // huart == UART4
{
memcpy(m_modulePort.txBuffer, m_meterPort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_modulePort.huart, m_modulePort.txBuffer, Size);
StartDMAReceptionOverUART4();
}
else if (huart->Instance == m_modulePort.huart->Instance) // huart == UART1
{
memcpy(m_meterPort.txBuffer, m_modulePort.rxBuffer, Size);
HAL_UART_Transmit_DMA(m_meterPort.huart, m_meterPort.txBuffer, Size);
}
else
{
return;
}
}
Callback function, in dependence of the periphery, will copy received data to a buffer and send it to the other periphery (functions memcpy() and HAL_UART_Transmit_DMA()). DMA over UART4 is in Normal mode, therefore StartDMAReceptionOverUART4() is called, inside which is HAL_UARTEx_ReceiveToIdle_DMA(). On the other hand, DMA over UART1 is in Circular mode, so there is no need for calling StartDMAReceptionOverUART4().

STM32 HAL I2C Slave Interrupts Stop Working

I'm working with an STM32 (STM32F030K6TX) with the HAL Library. The STM32 functions as a slave device, all events are triggered by interrupts by events from the master MCU (Jetson Nano), interrupting the main loop running on the STM32. Upon resetting the device, the I2C works for a period of time, fulfilling several I2C requests before it stops working. When this happens the interrupts stop firing on the STM32 and all I2C reads/writes from the master MCU time out. The main loop is still active.
I noticed the HAL_I2C_GetError(&hi2c1) = HAL_I2C_ERROR_AF after these events. I tried to see if I could disable and re-enable the I2C to fix the interrupts, but it does not work. The code restores the state of the I2C to listening and clears the errors, but the interrupts still do not fire.
Does anyone know what might be the cause of these errors, and/or logic that can restore the I2C to a good state if this occurs?
MX_DMA_Init();
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC_Init();
MX_I2C1_Init();
MX_TIM3_Init();
MX_DMA_Init();
MX_TIM14_Init();
/* USER CODE BEGIN 2 */
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
transferState = 0;
while (1)
{
// 2) Respond to I2C Requests
if (transferState == 1) {
transferState = 2;
if (transferDirection == I2C_DIRECTION_TRANSMIT) {
// Receive a message from the Jetson, it's telling us to do something!
HAL_StatusTypeDef receiveState = HAL_I2C_Slave_Seq_Receive_DMA(&hi2c1, (uint8_t *)jetsonRequestRX, RXBUFFERSIZE, I2C_FIRST_AND_LAST_FRAME);
if(receiveState != HAL_OK)
{
Error_Handler();
}
} else {
// State is listen. This request fails... why?
if(HAL_I2C_Slave_Seq_Transmit_DMA(&hi2c1, (uint8_t *)jetsonTransmitPos, TXBUFFERSIZE, I2C_FIRST_AND_LAST_FRAME) != HAL_OK)
{
Error_Handler();
}
reset_calibration();
}
}
// This code attempts to detect the error condition and fix the I2C interrupts, but does not work
else if (transferState == 0) {
if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF) {
HAL_I2C_DeInit(&hi2c1);
HAL_I2C_Init(&hi2c1);
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
/* Transfer error in reception process */
Error_Handler();
}
}
}
// *** ... Main loop ...
}
/* USER CODE BEGIN 4 */
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *i2cHandle) {
transferState = 0;
}
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *i2cHandle) {
jetsonRequest[0] = jetsonRequestRX[0];
jetsonRequest[1] = jetsonRequestRX[1];
transferState = 0;
}
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
/* restart listening for master requests */
if(HAL_I2C_EnableListen_IT(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
UNUSED(AddrMatchCode);
if(transferState == 0) {
transferState = 1;
transferDirection = TransferDirection;
}
}
the slave and listen hal is not very robust nor simple to use
i had use it very rarely and with hard time always
i remenber the hal handle do have some internal state or alike that went wrong in rare or unexpected error or if you rd/Wr less data than initaly expected or you don't do "right" (wjat they expect you) on the callback.
In this case it wan't restart operating correctly until state it's not hacked.
Try hanlding all hal error callback to see if their'ss any error thrown before it get screwd.
I don't have the f/W working in slave mode right now with me to help more :/

STM32F4 SPI interrupts stop firing with FreeRTOS

I'm trying to make an SPI communication between a F410 MCU and a RPi using SPI.
I post below the code that currently works (without FreeRTOS usage):
main.c
volatile int tx_done = 0;
volatile int rx_done = 0;
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
tx_done = 1;
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
rx_done = 1;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI5_Init();
MX_USART2_UART_Init();
const uint8_t BUF_SIZE = 16 * sizeof(uint8_t);
uint8_t buf[16];
// For UART debug
uint8_t dbg_buffer[64];
while (1) {
memset(buf, 0, BUF_SIZE);
HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, BUF_SIZE);
while (rx_done == 0) {};
rx_done = 0;
sprintf((char*) dbg_buffer, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d]\r\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
buf[7], buf[8], buf[9], buf[10], buf[11], buf[12],
buf[13], buf[14], buf[15]);
HAL_UART_Transmit(&huart2, dbg_buffer, strlen((char const*) dbg_buffer), 50);
HAL_SPI_Transmit_IT(&hspi5, (uint8_t*) &buf, BUF_SIZE);
while (tx_done == 0) {};
tx_done = 0;
}
}
stm32f4xx_it.c
/**
* #brief This function handles TIM1 trigger and commutation interrupts and TIM11 global interrupt.
*/
void TIM1_TRG_COM_TIM11_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim11);
}
/**
* #brief This function handles SPI5 global interrupt.
*/
void SPI5_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi5);
}
spi.c
/* SPI5 init function */
void MX_SPI5_Init(void)
{
hspi5.Instance = SPI5;
hspi5.Init.Mode = SPI_MODE_SLAVE;
hspi5.Init.Direction = SPI_DIRECTION_2LINES;
hspi5.Init.DataSize = SPI_DATASIZE_8BIT;
hspi5.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi5.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi5.Init.NSS = SPI_NSS_HARD_INPUT;
hspi5.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi5.Init.TIMode = SPI_TIMODE_DISABLE;
hspi5.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi5.Init.CRCPolynomial = 15;
if (HAL_SPI_Init(&hspi5) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
[...]
HAL_NVIC_SetPriority(SPI5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI5_IRQn);
}
This working fine with my test code on the other (raspberry pi) side, sending a SPI frame every second, waiting 100ms and reading the answer from the F410.
Now, when I activate FreeRTOS, I move the while(1) loop content to a task, and creates it with
BaseType_t task1 = xTaskCreate(task_1, "task_1", 512, NULL, tskIDLE_PRIORITY, &xHandle);
and osKernelStart(). I also use the TIM11 as Timebase Source (under SYS tab on CubeMX as advised by the software itself)
Then I have the following behavior: If I place breakpoints inside both Tx/Rx SPI interrupt, I found that a couple (3-4 ?) of them are fired, then never again. If I stop my code I see I'm stucked in the
while (rx_done == 0) {};
loop, confirming that I don't get SPI RX interrupts anymore whereas there is still frame coming on the SPI bus.
To dig a little into that theory, I made another test with this in my task:
while(1) {
memset(buf, 0, 16);
HAL_StatusTypeDef ret = HAL_SPI_Receive_IT(&hspi5, (uint8_t*)&buf, 16);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
// Wait for RX interrupt, task is suspended to give processing time to (incoming) others tasks
vTaskSuspend(NULL);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
}
and in my Rx interrupt, I simply call
xTaskResumeFromISR(task1Handle);
With this code, the first packet sent is read correctly by the STM32F4, and task print it on USART2 and suspend itself again. From then, (checked with a breakpoint inside), the Rx interrupt is never called again, so the task resume inside neither, and my code is frozen...
It really looks like there is a messing between FreeRTOS and STM32 HAL SPI/interrupt handling ?
Any help will be gladly accepted !
Do you call NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); as described in the red text on this page: https://www.freertos.org/RTOS-Cortex-M3-M4.html ?
If you are using an STM32 with the STM32 driver library then ensure all the priority bits are assigned to be preempt priority bits by calling NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); before the RTOS is started.

STM32F407 UART Communication

I am trying to set up a communication between my STM32F4 - Discovery with Open 407V-D development board and a peripheral using UART3 as a RS-485 bus.
I have problem with my communication becouse Rx state of UART remain busy.
Could somebody please explain me what am I doing wrong?
Should I somehow edit HAL_UART_IRQHandler or what setting am I missing?
Here is my code:
#include "main.h"
#include "stm32f4xx_hal.h"
UART_HandleTypeDef huart3;
uint8_t Ocular_1_RxBuffer[4];
uint8_t Ocular_1_TxBuffer[2] = {0x01,0x86};
__IO ITStatus UartReady;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART3_UART_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET); //set RS 485 into transmit mode
while (1)
{
int Timeout = 1000000;
while(huart3.gState != HAL_UART_STATE_READY) //wait for UART
{
Timeout--;
if(Timeout == 0)
Error_Handler();
}
Timeout = 1000000;
if(HAL_UART_Transmit_IT(&huart3, (uint8_t*)Ocular_1_TxBuffer, 2) != HAL_OK) //Send request
{
Error_Handler();
}
while(huart3.RxState != HAL_UART_STATE_READY) //wait for UART
{
Timeout--;
if(Timeout == 0)
Error_Handler();
}
Timeout = 1000000;
if(HAL_UART_Receive_IT(&huart3, (uint8_t*)Ocular_1_RxBuffer, 4) != HAL_OK) //Response
{
Error_Handler();
}
while(UartReady == RESET) //Wait for response
{
Timeout--;
if(Timeout == 0)
Error_Handler();
}
}
}
I have successfully received response from my peripheral device, but my code generate Error_Handler() after HAL_UART_RxCpltCallback() function.
Could somebody please explain this behavior to me?
My callback functions:
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
{
/* Set transmission flag: transfer complete */
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);
UartReady = RESET;
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
/* Set transmission flag: transfer complete */
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
UartReady = SET;
}
Please mention the number of bytes you are receiving in current scenario.?
Some debugging tips are -
Try increasing the size of your buffer and check if you are receiving any data.
Make sure you are re initialising your buffer after 4 bytes are read. If not the buffer can overflow and may lead to error handler.
Make sure you transmitter always sends 4 bytes.
Confirm if your buad rate matches on both devices. Also settings like parity and all are same in receiver and transmitter.
After every 4 bytes you need to call the HAL_UART_Receive_IT() again to configure and wait for next interrupt.
Add Error callback too, and confirm if execution moves to this callback. If then add prints in driver to find out whats the error cause, whether its like overrun error / Noise error / Parity Error etc.