stm32 HAL CAN receive massage in normal mode, it receives but does not come out of interrupt - stm32

I wrote a simple code as below for receiving data via can bus.
I have a board and a can bus analyzer for testing. I send data from analyzer to the board.
in debug mode I saw that the data is received correctly, the "data_received" variable is set to '1' too, but the "b" variable has not changed.
it seems that we dont come out of the interrupt function and dont come to while(1)
#include "main.h"
CAN_HandleTypeDef hcan1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN1_Init(void);
CAN_RxHeaderTypeDef RxHeader;
uint8_t data[2];
volatile int data_received=0;
volatile int b=0;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance==CAN1)
{
HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0,&RxHeader,data);
}
if (RxHeader.DLC==2)
{
data_received=1;
}
else
{
data_received=0;
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_CAN1_Init();
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING)!= HAL_OK)
{
Error_Handler();
}
while (1)
{
if (data_received==1)
{
b=1;
data_received=0;
}
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
static void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 3;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_11TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
CAN_FilterTypeDef canfilterconfig;
canfilterconfig.FilterActivation = CAN_FILTER_ENABLE;
canfilterconfig.FilterBank = 18;
canfilterconfig.FilterFIFOAssignment = CAN_RX_FIFO0;
canfilterconfig.FilterIdHigh = 0x103<<5;
canfilterconfig.FilterIdLow = 0x0000;
canfilterconfig.FilterMaskIdHigh = 0x103<<5;
canfilterconfig.FilterMaskIdLow = 0x0000;
canfilterconfig.FilterMode = CAN_FILTERMODE_IDMASK;
canfilterconfig.FilterScale = CAN_FILTERSCALE_32BIT;
canfilterconfig.SlaveStartFilterBank = 20;
HAL_CAN_ConfigFilter(&hcan1, &canfilterconfig);
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11, GPIO_PIN_SET);
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif

Have a look inside HAL_CAN_GetRxMessage function, all eight data array bytes are always initialized:
aData[0] = (uint8_t)((CAN_RDL0R_DATA0 & hcan->Instance->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA0_Pos);
aData[1] = (uint8_t)((CAN_RDL0R_DATA1 & hcan->Instance->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA1_Pos);
aData[2] = (uint8_t)((CAN_RDL0R_DATA2 & hcan->Instance->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA2_Pos);
aData[3] = (uint8_t)((CAN_RDL0R_DATA3 & hcan->Instance->sFIFOMailBox[RxFifo].RDLR) >> CAN_RDL0R_DATA3_Pos);
aData[4] = (uint8_t)((CAN_RDH0R_DATA4 & hcan->Instance->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA4_Pos);
aData[5] = (uint8_t)((CAN_RDH0R_DATA5 & hcan->Instance->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA5_Pos);
aData[6] = (uint8_t)((CAN_RDH0R_DATA6 & hcan->Instance->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA6_Pos);
aData[7] = (uint8_t)((CAN_RDH0R_DATA7 & hcan->Instance->sFIFOMailBox[RxFifo].RDHR) >> CAN_RDH0R_DATA7_Pos);
Yet your data array is only two bytes long. HAL_CAN_GetRxMessage overrites other variables. This might not be your problem, but it's an obvious bug that will bite you eventually.
Note, that after compilation, order of the variables might not be the same as in the source. You might think that data_received is getting overriten, but it might not. To find out actual order of the variables you can look at the map file.

Related

STM32 enters stop mode on reset

I am trying out stop mode in STM32F103x which is by the way a clone. I have a timer that counts up to five seconds and then sets a variable "goTosleep" = 1 on interrupt. Depending on the value of goTosleep I execute Stop command. I can exit the stop mode via EXTI. The problem is that the micro controller appears to enter stop mode upon reset. It exits stop mode fine when I give an interrupt on EXTI.
Here is my code.
#include "main.h"
TIM_HandleTypeDef htim2;
uint8_t goTosleep = 0;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HAL_TIM_Base_Start_IT(&htim2);
while (1)
{
HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin);
HAL_Delay(100);
if(goTosleep == 1)
{
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
SystemClock_Config();
}
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 7200-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 50000-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin : led_Pin */
GPIO_InitStruct.Pin = led_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(led_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PB15 */
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim2)
{
goTosleep = 1;
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
__HAL_TIM_SET_COUNTER(&htim2, 0);
goTosleep = 0;
}
/* USER CODE END 4 */
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
There is a possibility that the timer interrupt routine runs once after starting the timer. So put a guard variable in the callback function:
uint8_t first_time = 0; // global
...
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (first_time != 0)
{
if(htim == &htim2)
{
goTosleep = 1;
}
}
first_time = 1;
}

STM32: analog watchdog does only trigger interrupt HAL_ADC_LevelOutOfWindowCallback once

Question
Do I need to reset the analog watchdog each time it triggers an
interrupt or is there an error in my code ?
If I need to reset it every time how would I do that ?
Is there a HAL function for it that I can call in the callback?
My Code
Main
HAL_ADC_Start(&hadc2);
ADC and WDG Config
static void MX_ADC2_Init(void){
ADC_AnalogWDGConfTypeDef AnalogWDGConfig = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/** Common config*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc2.Init.Resolution = ADC_RESOLUTION_8B;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc2.Init.LowPowerAutoWait = DISABLE;
hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Analog WatchDog 1 */
AnalogWDGConfig.WatchdogNumber = ADC_ANALOGWATCHDOG_1;
AnalogWDGConfig.WatchdogMode = ADC_ANALOGWATCHDOG_SINGLE_REG;
AnalogWDGConfig.HighThreshold = 64-1;
AnalogWDGConfig.LowThreshold = 0;
AnalogWDGConfig.Channel = ADC_CHANNEL_1;
AnalogWDGConfig.ITMode = ENABLE;
if (HAL_ADC_AnalogWDGConfig(&hadc2, &AnalogWDGConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
The Callback
void HAL_ADC_LevelOutOfWindowCallback (ADC_HandleTypeDef * hadc){
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);
}
Looking at your code... specifically...
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV
You probably just need to call start again after the interrupt...
HAL_ADC_Start(&hadc2);

DMA in EVE board 3

I am trying to do DMA in eve3-43inch LCD TFT ( matrix orbital), TFT screen working without DMA but as soon I add DMA settings DMA does not respond ing. What might be the reason? I using EVE81.h library. These codes I have added to make SPI initialization with DMA.
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 */
/* USER CODE END SPI1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PB5 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA2_Stream0;
hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA2_Stream3;
hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_CIRCULAR; //DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;//DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
}
}
Here I am transmitting as DMA or normal way. These codes working without DMA. After making it to transmit or receive through DMA LCD not responding.
void HAL_SPI_WriteBuffer(uint8_t *Buffer, uint32_t Length)
{
HAL_SPI_Enable();
volatile int result = HAL_SPI_Transmit(&hspi1, Buffer, Length, 1000);
//volatile int result = HAL_SPI_Transmit_DMA(&hspi1, Buffer, Length);
HAL_SPI_Disable();
}
void HAL_SPI_ReadBuffer(uint8_t *Buffer, uint32_t Length)
{
//EVE requires one dummy read/write before actual data can be read
Buffer[0] = 0;
volatile int result = HAL_SPI_Transmit(&hspi1, Buffer, 1, 1000);
HAL_SPI_Receive(&hspi1, Buffer, Length,1000);
//volatile int result = HAL_SPI_Transmit_DMA(&hspi1, Buffer, 1);
//HAL_SPI_Receive_DMA(&hspi1, Buffer, Length);
}
uint8_t HAL_SPI_Write(uint8_t data)
{
//volatile int result = HAL_SPI_Transmit(&hspi1, &data, 1, 1000);
volatile int result = HAL_SPI_Transmit_DMA(&hspi1, &data, 1);
return 0;
}

spi master fires uncontrollable dma tc interrupts without receiving nothing

I've already asked this question on the mbed forum, but I did not received an answer.
Introduction
I have two Nucleo L432kc board, I want to make them communicate with the SPI protocol using DMA.
In the following scheme you can see the actual hardware setup:
What works
If I send data from the master to the slave I receive them correctly and when the master is not transmitting the slave does not receive anything.
Master's code
#include <mbed.h>
uint8_t dma_buffer_tx[4];
uint8_t dma_buffer_rx[4];
uint8_t buff[4];
uint32_t receive_buff_length = 4;
unsigned int c = 0;
Serial pc(USBTX,USBRX,921600);
DigitalOut led(LED3);
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;
void Error_Handler(){
led.write(1);
while(1){}
}
static void HAL_GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi1.Instance==SPI1)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA1 ------> SPI1_SCK
PA11 ------> SPI1_MISO
PA12 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else
Error_Handler();
}
static void SPI1_Init(void)
{
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
}
static void DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA1_Channel2;
hdma_spi1_rx.Init.Request = DMA_REQUEST_1;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmarx,hdma_spi1_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Request = DMA_REQUEST_1;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmatx,hdma_spi1_tx);
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
extern "C"{
void DMA1_Channel3_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_tx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_rx);
}
void SPI1_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi1);
}
}
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = 0; i < receive_buff_length/2; i++){
buff[i] = dma_buffer_rx[i];
}
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = receive_buff_length/2; i < receive_buff_length; i++){
buff[i] = dma_buffer_rx[i];
}
printf("%u\n",*(unsigned int *)buff); // to understan when I am actually receiving data
memset(dma_buffer_rx,0,sizeof(dma_buffer_rx));
}
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
c += 5;
dma_buffer_tx[0] = c & 0xFF;
dma_buffer_tx[1] = (c >> 8) & 0xFF;
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi1){
dma_buffer_tx[2] = (c >> 16) & 0xFF;
dma_buffer_tx[3] = (c >> 24) & 0xFF;
}
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* SPI INIT */
SPI1_Init();
/* GPIO USART2 INIT */
HAL_GPIO_Init();
/* DMA INIT */
DMA_Init();
c = 1000;
dma_buffer_rx[0] = c & 0xFF;
dma_buffer_rx[1] = (c >> 8) & 0xFF;
dma_buffer_rx[2] = (c >> 16) & 0xFF;
dma_buffer_rx[3] = (c >> 24) & 0xFF;
while(true){
HAL_SPI_Transmit_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
wait(0.001);
}
}
Slave's code
#include <mbed.h>
uint8_t dma_buffer_tx[4];
uint8_t dma_buffer_rx[4];
uint8_t buff[4];
uint32_t receive_buff_length = 4;
unsigned int c = 0;
Serial pc(USBTX,USBRX,921600);
DigitalOut led(LED3);
SPI_HandleTypeDef hspi1;
DMA_HandleTypeDef hdma_spi1_rx;
DMA_HandleTypeDef hdma_spi1_tx;
void Error_Handler(){
led.write(1);
while(1){}
}
static void HAL_GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi1.Instance==SPI1)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA1 ------> SPI1_SCK
PA11 ------> SPI1_MISO
PA12 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
else
Error_Handler();
}
static void SPI1_Init(void)
{
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_SLAVE;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.CRCPolynomial = 7;
hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
}
static void DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA1_Channel2;
hdma_spi1_rx.Init.Request = DMA_REQUEST_1;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmarx,hdma_spi1_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA1_Channel3;
hdma_spi1_tx.Init.Request = DMA_REQUEST_1;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hspi1,hdmatx,hdma_spi1_tx);
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
}
extern "C"{
void DMA1_Channel3_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_tx);
}
void DMA1_Channel2_IRQHandler(void)
{
HAL_NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
HAL_DMA_IRQHandler(&hdma_spi1_rx);
}
void SPI1_IRQHandler(void)
{
HAL_SPI_IRQHandler(&hspi1);
}
}
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = 0; i < receive_buff_length/2; i++){
buff[i] = dma_buffer_rx[i];
}
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi1){
for(int i = receive_buff_length/2; i < receive_buff_length; i++){
buff[i] = dma_buffer_rx[i];
}
printf("%u\n",*(unsigned int *)buff); // to understan when I am actually receiving data
memset(dma_buffer_rx,0,sizeof(dma_buffer_rx));
}
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi1){
c += 5;
dma_buffer_tx[0] = c & 0xFF;
dma_buffer_tx[1] = (c >> 8) & 0xFF;
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi1){
dma_buffer_tx[2] = (c >> 16) & 0xFF;
dma_buffer_tx[3] = (c >> 24) & 0xFF;
}
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* SPI INIT */
SPI1_Init();
/* GPIO USART2 INIT */
HAL_GPIO_Init();
/* DMA INIT */
DMA_Init();
c = 1000;
dma_buffer_rx[0] = c & 0xFF;
dma_buffer_rx[1] = (c >> 8) & 0xFF;
dma_buffer_rx[2] = (c >> 16) & 0xFF;
dma_buffer_rx[3] = (c >> 24) & 0xFF;
while(true){
HAL_SPI_Receive_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
}
}
What does not work
If I change the role in the communication, so I send the data from the salve to the master swapping the following lines
[...]
HAL_SPI_Transmit_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
wait(0.001);
[...]
with:
[...]
HAL_SPI_Receive_DMA(&hspi1,dma_buffer_rx,receive_buff_length);
[...]
Even if the slave is not powered up the master continusly receives interrupts and invokes the HAL_SPI_RxCpltCallback. If we power up the slave the master prints random numbers.
What I have already tried without success
I've tested the master code on a Nucleo F446 board.
I've set pull-down and pull-up resistors on the MISO pin.
I've tried different cable for the hw connection.
I've tried to directly use the HAL_SPI_TransmitReceive_DMA function, but the behaviour is the same.
Considerations
Walking throught the HAL_SPI_Receive_DMA source I've noticed that in the SPI_MODE_MASTER the HAL_SPI_TransmitReceive_DMA fuction is actually called.
I think that the same buffer is used for transmission and reception, but I don't know how to prove that.
I've also printed the hdma_spi1_rx.Instance->CNDTR and I've noticed that the value increments to 4 whitch is actually the number of bytes that we are going to receive.
SPI master always receives data when it is transmitting. This is how the SPI works. Even if the SPI is not transmitting, the master reads the data all the time.

How do I use the STM32CUBEF4 HAL library to read out the sensor data with i2c?

I want to use the latest HAL library instead of Standard Peripheral Library.
And i want to readout the BMA250E G-sensor's chip_id, but it doesn't work.
Value of aRxBuffer always keep at 0x00. But it should be 0xf9!
What's wrong in my code?
‪#‎include‬ "stm32f4xx_hal.h"
#define I2Cx_SDA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define I2Cx_SDA_PIN GPIO_PIN_9
#define I2Cx_SDA_GPIO_PORT GPIOB
#define I2Cx_SDA_AF GPIO_AF4_I2C1
#define I2Cx_SCL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define I2Cx_SCL_PIN GPIO_PIN_6
#define I2Cx_SCL_GPIO_PORT GPIOB
#define I2Cx_SCL_AF GPIO_AF4_I2C1
#define I2Cx_CLK_ENABLE() __HAL_RCC_I2C1_CLK_ENABLE()
#define I2Cx_FORCE_RESET() __HAL_RCC_I2C1_FORCE_RESET()
#define I2Cx_RELEASE_RESET() __HAL_RCC_I2C1_RELEASE_RESET()
‪#‎define‬ I2C_ADDRESS 0x18
static void SystemClock_Config(void);
uint8_t aTxBuffer[2],aRxBuffer;
int main()
{
HAL_Init();
SystemClock_Config();
I2C_HandleTypeDef I2cHandle;
I2cHandle.Instance = I2C1;
I2cHandle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
I2cHandle.Init.ClockSpeed = 400000;
I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
I2cHandle.Init.DutyCycle = I2C_DUTYCYCLE_16_9;
I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
I2cHandle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
I2cHandle.Init.OwnAddress1 = 0;
I2cHandle.Init.OwnAddress2 = 0;
HAL_I2C_Init(&I2cHandle);
aTxBuffer[0]=0x00;
HAL_I2C_Master_Transmit(&I2cHandle, I2C_ADDRESS,aTxBuffer, 1, 10000);
HAL_I2C_Master_Receive(&I2cHandle,I2C_ADDRESS|0x01 ,&aRxBuffer, 1, 10000);
HAL_Delay(1000);
}
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType =
(RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2Cx_SCL_GPIO_CLK_ENABLE();
I2Cx_SDA_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = I2Cx_SCL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = I2Cx_SCL_AF;
HAL_GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = I2Cx_SDA_PIN;
GPIO_InitStruct.Alternate = I2Cx_SDA_AF;
HAL_GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct);
}
void HAL_I2C_MspDeInit(I2C_HandleTypeDef *hi2c)
{
I2Cx_FORCE_RESET();
I2Cx_RELEASE_RESET();
HAL_GPIO_DeInit(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN);
HAL_GPIO_DeInit(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN);
}
First, I would advise you to use STMCube. It will set up the clock and the I2C bus for you.
It is very good practice to check what the HAL functions return. If you don't have HAL_OK, something went wrong.
Try at 100KHz first, and then increase to 400KHz.
The I2C address of the device is 0x18 (if SDO is grounded, which I assume it is). But in the HAL driver, you have to define:
#‎define‬ I2C_ADDRESS (0x18<<1)
What you want to do is to read a register, so don't use HAL_I2C_Master_Receive or HAL_I2C_Master_Transmit, but HAL_I2C_Mem_Read or HAL_I2C_Mem_Write, like this:
#define REG_CHIP_ID 0x00
HAL_I2C_Mem_Read(&I2cHandle, I2C_ADDRESS, REG_CHIP_ID, I2C_MEMADD_SIZE_8BIT, &aRxBuffer, 1, 10000);
Also, note that the HAL takes care of the R/W bit of the address, so you don't need to do:
I2C_ADDRESS|0x01