Related
I am implementing the bmi160 and bmm150 drivers from Bosch in order to get data from the BMX160 (pinout board made by DFRobot) because from what I have gathered. I changed the chip id to match the bmx160 chip id. Upon all the initializations I am given valid returns of 0 yet when I get to reading the data, I do not get good data from the chip. I have made sure the device is getting voltage and is found by my board (STM32F0). I2C clock is set to the standard mode with a default clock speed.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* #file : main.c
* #brief : Main program body
******************************************************************************
* #attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "bmm150.h"
#include "bmi160.h"
#include <stdio.h>
// #include "stm32f0xx_hal_uart.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
// UART_HandleTypeDef huart1;
struct bmi160_dev bmi;
struct bmm150_dev bmm;
struct bmm150_settings bmm_settings;
struct bmm150_mag_data mag;
struct bmi160_sensor_data accel;
struct bmi160_sensor_data gyro;
int8_t rslt, rslt1, rslt2, rslt3, rslt4, rslt5, rslt6, rslt7;
int8_t rslt_data, rslt_data1, rslt_data2;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
// static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
/* Auxiliary function declarations */
int8_t bmm150_aux_read(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, void *intf_ptr);
int8_t bmm150_aux_write(uint8_t reg_addr, uint8_t *aux_data, uint16_t len, void *intf_ptr);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint8_t Buffer[25] = {0};
uint8_t Space[] = " - ";
uint8_t StartMSG[] = "Starting I2C Scanning: \r\n";
uint8_t EndMSG[] = "Done! \r\n\r\n";
int8_t user_i2c_read(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
HAL_StatusTypeDef status = HAL_OK;
while (HAL_I2C_IsDeviceReady(&hi2c1, (uint8_t)(id << 1), 3, 100) != HAL_OK)
{
rslt = 0;
}
status = HAL_I2C_Master_Transmit(&hi2c1, (uint8_t)(id << 1), ®_addr, 1, 1000);
if (status != HAL_OK)
{
rslt = (-1);
}
HAL_Delay(100);
status = HAL_I2C_Master_Receive(&hi2c1, (uint8_t)(id << 1), data, len, 10000);
if (status != HAL_OK)
{
rslt = (-1);
}
return rslt;
}
int8_t user_i2c_write(uint8_t id, uint8_t reg_addr, uint8_t *data, uint16_t len)
{
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
HAL_StatusTypeDef status = HAL_OK;
while (HAL_I2C_IsDeviceReady(&hi2c1, (uint8_t)(id << 1), 3, 100) != HAL_OK)
{
}
uint8_t tx_buffer[len + 1];
tx_buffer[0] = reg_addr;
memcpy(&tx_buffer[1], data, len);
status = HAL_I2C_Master_Transmit(&hi2c1, (uint8_t)(id << 1), tx_buffer, len + 1, 1000);
if (status != HAL_OK)
{
rslt = (-1);
}
return rslt;
}
void user_delay_ms(uint32_t period)
{
HAL_Delay(period);
}
/* USER CODE END 0 */
/**
* #brief The application entry point.
* #retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t i = 0, ret;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
// rslt = i2c_ping_device(&hi2c1, 0x00);
/* USER CODE BEGIN 2 */
bmi.id = BMI160_I2C_ADDR;
bmi.chip_id = BMI160_CHIP_ID;
bmi.intf = BMI160_I2C_INTF;
bmi.read = &user_i2c_read;
bmi.write = &user_i2c_write;
bmi.delay_ms = &user_delay_ms;
bmm.chip_id = BMM150_DEFAULT_I2C_ADDRESS;
bmm.intf = BMM150_I2C_INTF;
bmm.read = (bmm150_read_fptr_t)bmm150_aux_read;
bmm.write = (bmm150_write_fptr_t)bmm150_aux_write;
bmm.delay_us = &user_delay_ms;
bmm.intf_ptr = bmm.chip_id;
rslt = bmi160_init(&bmi);
// pingStatus = i2cs_ping_device(BMI160_I2C_ADDR);
bmi.aux_cfg.aux_sensor_enable = BMI160_ENABLE;
bmi.aux_cfg.aux_i2c_addr = bmm.chip_id;
bmi.aux_cfg.manual_enable = BMI160_ENABLE;
bmi.aux_cfg.aux_rd_burst_len = BMI160_AUX_READ_LEN_3;
rslt1 = bmi160_aux_init(&bmi);
rslt2 = bmm150_init(&bmm);
bmi.accel_cfg.odr = BMI160_ACCEL_ODR_100HZ;
bmi.accel_cfg.range = BMI160_ACCEL_RANGE_2G;
bmi.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;
bmi.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;
bmi.gyro_cfg.odr = BMI160_GYRO_ODR_100HZ;
bmi.gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS;
bmi.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;
bmi.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE;
rslt3 = bmi160_set_sens_conf(&bmi);
bmm_settings.preset_mode = BMM150_PRESETMODE_REGULAR;
rslt4 = bmm150_set_presetmode(&bmm_settings, &bmm);
bmm_settings.pwr_mode = BMM150_POWERMODE_FORCED;
rslt5 = bmm150_set_op_mode(&bmm_settings, &bmm);
uint8_t aux_addr = 0x42;
uint8_t mag_data[8] = {0};
uint8_t index;
bmi.aux_cfg.aux_odr = 8;
rslt6 = bmi160_config_aux_mode(&bmi);
rslt7 = bmi160_set_aux_auto_mode(BMM150_REG_CHIP_ID, &bmi);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
user_delay_ms(100);
rslt_data = bmi160_get_sensor_data((BMI160_ACCEL_SEL | BMI160_GYRO_SEL), &accel, &gyro, &bmi);
rslt_data1 = bmi160_read_aux_data_auto_mode(mag_data, &bmi);
rslt_data2 = bmm150_aux_mag_data(mag_data, &mag, &bmm);
/* USER CODE END WHILE */
printf("****************\n");
printf("ACC X: %d, Y: %d, Z: %d\n", accel.x, accel.y, accel.z);
printf("GYRO X: %d, Y: %d, Z: %d\n", gyro.x, gyro.y, gyro.z);
printf("MAG X : %d Y : %d Z : %d\n", mag.x, mag.y, mag.z);
printf("################\n");
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* #brief System Clock Configuration
* #retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* #brief I2C1 Initialization Function
* #param None
* #retval None
*/
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x200009FE;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
// static void MX_USART1_UART_Init(void)
// {
// /* USER CODE BEGIN USART1_Init 0 */
// /* USER CODE END USART1_Init 0 */
// /* USER CODE BEGIN USART1_Init 1 */
// /* USER CODE END USART1_Init 1 */
// 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();
// }
// /* USER CODE BEGIN USART1_Init 2 */
// /* USER CODE END USART1_Init 2 */
// }
/**
* #brief GPIO Initialization Function
* #param None
* #retval None
*/
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* #brief This function is executed in case of error occurrence.
* #retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
int8_t bmm150_aux_read(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, void *intf_ptr)
{
int8_t rslt;
rslt = bmi160_aux_read(reg_addr, reg_data, len, &bmi);
return rslt;
}
int8_t bmm150_aux_write(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, void *intf_ptr)
{
int8_t rslt;
rslt = bmi160_aux_write(reg_addr, reg_data, len, &bmi);
return rslt;
}
#ifdef USE_FULL_ASSERT
/**
* #brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* #param file: pointer to the source file name
* #param line: assert_param error line source number
* #retval None
*/
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,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
The print statements in the while loop are supposed to provide the results. The Accel data and Gyro data both are 0 for x,y,z and 0 on the sensor time. The mag data provides -32768 for the x,y,z values. I have checked that all functions return 0 several times but still I am confused on why I am not getting good data. I am also using the latest code from Bosch's github repo for both the bmi160 and bmm150.
Here is the I2C configure that is called by the MX_12C1_INIT().
void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (hi2c->Instance == I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB8 ------> I2C1_SCL
PB9 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
This is using a STM32F030R8T6 Processor that is supplied voltage by a st-link-v2.
When creating circuitry, a number of issues could arise during the process which we are not aware of. A common issue is powering one are of the circuit with one voltage and communicating with the circuit using a different voltage. Both sensor and PLC need to be running on same voltage over the comms channel / pins.
The next step to debugging a circuit in this case would be to ensure that your "breakout board" or the sensor have pull up resistors. I have always found (40-50 different samples) that I do not need to add pull up resistors to break out boards. I have never had to add any.
The next issue I usually run into is addressing. Most ICs / sensors have a mechanism which allows you to select which address to use. If you hold the voltage low (0v), it will have a certain address while if you hold the voltage high (3.3v or 5v or whatever) it might be a different address. If you failed to add any connector to the pin (floating), it will be invalid and sensor will not start.
Another common issue is protocol. Some chips enable certain protocols by default and you may need to modify the internal settings in order to change them. By protocol, I am referring to either I2C, SPI or U(S)ART. This is unlikely but I've added it for completeness.
The issue most people think is happening is that the sensor is fried due to ESD. The likelyhood of your circuit being damaged is wildly low and it is certainly stronger than you think. I doubt you have damaged the circuit in any way.
To answer further, i would certainly require a picture of your circuit as the driver code should not be an issue at all. I generally find that driver code, even when outdated or for an earlier model, will generally still gather simple data relative to the ealier model.
I have a small program running on stm32wb55. It tests the TIM2 timer with a delay function called wait_us(). The program runs correctly when I compile it with Keil uVision 5, but when I compile it with STM32CubeIDE it gets stuck in the function get_us(). Is there a bug in STM32CubeIDE?
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void PeriphCommonClock_Config(void);
static void MX_GPIO_Init(void);
/* USER CODE BEGIN PFP */
extern void initialize_tim2(void);
extern void wait_us(volatile uint32_t us);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* #brief The application entry point.
* #retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* Configure the peripherals common clocks */
PeriphCommonClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
initialize_tim2();
TIM2->CR1 |= 0x0001;
wait_us(10);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin(GPIOB, LD1_Pin);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
#include "stm32wbxx.h"
volatile uint32_t tim2_counter;
void initialize_tim2(void)
{
RCC->APB1ENR1 |= 0x00000001;
TIM2->CR1 = 0x0004;
TIM2->CR2 = 0x0000;
TIM2->PSC = 0;
TIM2->ARR = 32;
TIM2->DIER = 0x0001;
TIM2->CNT = 0;
NVIC_SetPriority(TIM2_IRQn, 0);
tim2_counter = 0;
}
void TIM2_IRQHandler(void)
{
TIM2->SR &= (~0x001F);
++tim2_counter;
}
uint32_t get_us(void)
{
return tim2_counter;
}
void wait_us(volatile uint32_t us)
{
volatile uint32_t tickstart, now, IRQ_status;
// Get current interrupt status of TIM2 and enable it.
// Needs to be done with all interrupts disabled to prevent race condition?
__disable_irq();
IRQ_status = NVIC_GetEnableIRQ(TIM2_IRQn);
NVIC_EnableIRQ(TIM2_IRQn);
__enable_irq();
tickstart = get_us();
now = tickstart; //<-processing never reaches here under STM32CubeIDE.
while((now - tickstart) < us)
{
now = get_us();
}
// Return to previous interrupt status of TIM2.
// Needs to be done with all interrupts disabled to prevent race condition?
__disable_irq();
if(0 == IRQ_status)
{
NVIC_DisableIRQ(TIM2_IRQn);
}
else
{
NVIC_EnableIRQ(TIM2_IRQn);
}
__enable_irq();
}
I am first time using function pointers and ran into a weird problem. I am writing a code for STM32G4xx. The main idea is to transmit and receive data through LPUART. I have implemented simple FSM to handle TX and RX. LPUART configured in DMA interrupt mode. I have typedef the function pointer and declared the three function pointer variables (ISR handles) in main.h file as follow:
#ifndef __MAIN_H
#define __MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/* USER CODE BEGIN ET */
typedef void (*_func_clbck)(void);
/* USER CODE END ET */
_func_clbck lpuart_tx_tc_isr_clback;
//_func_clbck lpuart_rx_rne_isr_clback;
_func_clbck lpuart_dma_tx_tc_isr_clback;
_func_clbck lpuart_dma_rx_tc_isr_clback;
/* USER CODE END Private defines */
#ifdef __cplusplus
}
#endif
#endif /* __MAIN_H */
The definition of the function pointer is in function MX_LPUART1_UART_Init() in the main.c file.
#include "main.h"
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* System interrupt init*/
/* SysTick_IRQn interrupt configuration */
NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),1, 0));
/** Configure the internal voltage reference buffer voltage scale
*/
LL_VREFBUF_SetVoltageScaling(LL_VREFBUF_VOLTAGE_SCALE1);
/** Enable the Internal Voltage Reference buffer
*/
LL_VREFBUF_Enable();
/** Configure the internal voltage reference buffer high impedance mode
*/
LL_VREFBUF_DisableHIZ();
/** Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
*/
LL_PWR_DisableUCPDDeadBattery();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_LPUART1_UART_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
#ifdef LPUART_TEST
lpuart_init_test();
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LL_GPIO_ResetOutputPin(GPIOC,LL_GPIO_PIN_6);
//LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_6);
LL_mDelay(1);
uint8_t buf[9] ={'a','d','v',' ','l','o','w','\r','\n'};
//uint8_t buf[9] ={1,2,3,4,5,6,7,8,9};
#ifdef LPUART_TEST
uint16_t len_test[19] = {0,16,17,65535, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
for(uint16_t i = 0 ; i<19 ; i++){
set_len_rx_dma_buff(len_test[i]);
lpuart_rx_test();
}
#endif
static uint8_t once = 1;
while (1)
{
lpuart_task();
//delay_ms_DWT(1);
/*if(once){
once = 0;
lpuart_start_tx(buf, 9);
LL_mDelay(100);
}*/
if(1){
//lpuart_start_tx(buf, 9);
if(!lpuart_isTxBusy()){
lpuart_start_tx(buf, 9);
delay_ms_DWT(1);
if(!lpuart_isRxBusy()){
rxOldIndex += rxIndex;
if(rxOldIndex > 255){
rxOldIndex = 0;
rxIndex = 0;
}
rxIndex = RingBuffer_available(&lpuart_RX_ring_buff);
for(i = rxOldIndex ; i < (rxIndex+rxOldIndex) ; i++ ){
rxBuff[i] = RingBuffer_readMeas(&lpuart_RX_ring_buff);
}
}
}
}
//}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
static void MX_LPUART1_UART_Init(void)
{
/* USER CODE BEGIN LPUART1_Init 0 */
/* USER CODE END LPUART1_Init 0 */
LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Peripheral clock enable */
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
/**LPUART1 GPIO Configuration
PB10 ------> LPUART1_RX
PB11 ------> LPUART1_TX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* LPUART1 DMA Init */
/* LPUART1_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_LPUART1_TX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1_RX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMAMUX_REQ_LPUART1_RX);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1 interrupt Init */
NVIC_SetPriority(LPUART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(LPUART1_IRQn);
/* USER CODE BEGIN LPUART1_Init 1 */
/* USER CODE END LPUART1_Init 1 */
LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
LPUART_InitStruct.BaudRate = 9600;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
LL_LPUART_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
LL_LPUART_DisableFIFO(LPUART1);
LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_SWAPPED);
// LL_LPUART_EnableOverrunDetect(LPUART1);
// LL_LPUART_EnableDMADeactOnRxErr(LPUART1);
/* USER CODE BEGIN WKUPType LPUART1 */
/* USER CODE END WKUPType LPUART1 */
LL_LPUART_Enable(LPUART1);
/* Polling LPUART1 initialisation */
while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1))))
{
}
/* USER CODE BEGIN LPUART1_Init 2 */
//LL_LPUART_EnableIT_TXE_TXFNF(LPUART1);
/* Enable TC interrupts for RX */
/* Enable HT & TC interrupts for TX */
// LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
lpuart_tx_tc_isr_clback = LPUART_TX_TC_ISR_CALLBACK;
//lpuart_rx_rne_isr_clback = &LPUART_RX_RXNE_ISR_CALLBACK;
lpuart_dma_tx_tc_isr_clback = LPUART_DMA_TX_TC_CALLBACK;
lpuart_dma_rx_tc_isr_clback = LPUART_DMA_RX_TC_CALLBACK;
//LL_LPUART_EnableDirectionRx(LPUART1);
LL_LPUART_EnableDirectionTx(LPUART1);
//LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
/* USER CODE END LPUART1_Init 2 */
}
In main function, in while loop, I am calling the lpuart_start_tx(buf, 9); function just after the if(!lpuart_isTxBusy()) statement. This causes change of the address of the function pointer lpuart_dma_rx_tc_isr_clback but other two function pointers don't change its addresses and work fine. When an intrrupt raised on the reception of the data, it tried to execute lpuart_dma_rx_tc_isr_clback which causes the hard fault because its address was modified. Note that if I call lpuart_start_tx(buf, 9); before if(!lpuart_isTxBusy()), then everything works fine. I don't understand what could be an issue.
I have checked the CFSR register and every time different flag was raised. I have noticed that out of three flags, such as IBUSERR, IACCVOIL, and INVSTATE, one of them was raised. I have not included the full main.c file.
LPUART FSM implementation is as follow:
lpuart.h file
#ifndef INC_LPUART_H_
#define INC_LPUART_H_
#include "ring_buffer.h"
#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */
uint8_t lpuart_start_tx(uint8_t* buff, uint16_t len );
uint8_t LPUART_isTxFinished(void);
void LPUART_clear_tx_finishedFlag();
uint8_t lpuart_isRxBusy(void);
uint8_t lpuart_isTxBusy(void);
void lpuart_task();
void LPUART_TX_TC_ISR_CALLBACK(void);
void LPUART_DMA_TX_TC_CALLBACK(void);
void LPUART_DMA_RX_TC_CALLBACK(void);
#endif /* INC_LPUART_H_ */
lpuart.c
#include "lpuart.h"
#include "string.h"
#include "stm32g4xx_ll_lpuart.h"
#include "stm32g4xx_ll_dma.h"
#define SIZE_TX_BUFF 256
#define SIZE_RX_BUFF 256
#define SIZE_DMA_RX_BUFF 64
static uint8_t rxBuf[SIZE_RX_BUFF];
static uint8_t rxDMA_Buf[SIZE_DMA_RX_BUFF];
static uint8_t txBuf[SIZE_TX_BUFF];
RingBuffer lpuart_RX_ring_buff;
static uint8_t* tempTxBuf;
static uint16_t txLen = 0;
static void setTxDataLengthDMA(uint16_t len);
static void lpuart_transmit();
static void lpuart_finished_tx();
static void no_action();
static void lpuart_rx();
static void check_rx_dma_buff();
static uint8_t ev_no_event(void);
static uint8_t ev_txtc(void);
static uint8_t ev_start_tx(void);
static uint8_t ev_dmatxtc(void);
static uint8_t ev_rx_read(void);
static uint8_t ev_buff_full(void);
typedef uint8_t (*t_event_func)(void);
typedef void(*t_action_func)(void);
typedef struct{
uint16_t txtc:1;
uint16_t tx_busy:1;
uint16_t dmatxtc:1;
uint16_t dmarxtc:1;
uint16_t start_tx:1;
uint16_t rx_read:1;
uint16_t buff_full:1;
uint16_t is_fsm_table_init:1;
uint16_t ext_rxBusyFlag:1;
}t_event;
typedef enum {INIT, READY, BUSY, COMPLETE, LPUART_ERROR}t_state;
typedef struct{
t_state present_state;
t_event_func event1;
t_event_func event2;
t_action_func action1;
t_action_func action2;
t_state next_state;
}t_fsm_row;
typedef struct{
t_state current_state;
t_state previous_state;
t_fsm_row stt_row[7];
uint16_t number_of_rows;
}t_fsm_table;
t_event lpuart_event;
uint8_t lpuart_isTxBusy(void){
return lpuart_event.tx_busy;
}
uint8_t lpuart_isRxBusy(){
return lpuart_event.ext_rxBusyFlag;
}
uint8_t ev_no_event(void){
return 1;
}
uint8_t ev_txtc(void){
return lpuart_event.txtc;
}
uint8_t ev_start_tx(void){
return lpuart_event.start_tx;
}
uint8_t ev_dmatxtc(void){
return lpuart_event.dmatxtc;
}
uint8_t ev_rx_read(void){
return lpuart_event.rx_read || lpuart_event.dmarxtc;
}
uint8_t ev_buff_full(void){
return lpuart_event.buff_full;
}
void no_action(){
return;
}
void lpuart_init(void){
memset(rxBuf, 0, (size_t)SIZE_RX_BUFF );
memset(rxDMA_Buf, 0, (size_t)SIZE_DMA_RX_BUFF );
memset(txBuf, 0, (size_t)SIZE_TX_BUFF );
RingBuffer_init(&lpuart_RX_ring_buff,rxBuf , (uint16_t)SIZE_RX_BUFF);
LL_LPUART_DisableIT_TC(LPUART1);
LL_LPUART_DisableIT_RXNE_RXFNE(LPUART1);
LL_LPUART_DisableDirectionRx(LPUART1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1); //tx
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); //tx
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_2); //rx
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); //rx
/*TX buffer address attached to DMA channel1 */
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1,
(uint32_t)txBuf,
LL_LPUART_DMA_GetRegAddr(LPUART1, LL_LPUART_DMA_REG_DATA_TRANSMIT),
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, SIZE_TX_BUFF);
/*RX buffer address attached to DMA channel2 */
LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_2,
LL_LPUART_DMA_GetRegAddr(LPUART1, LL_LPUART_DMA_REG_DATA_RECEIVE),
(uint32_t)rxDMA_Buf,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, SIZE_DMA_RX_BUFF);
LL_LPUART_EnableDMAReq_RX(LPUART1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2); //rx
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); //rx
LL_LPUART_EnableDirectionRx(LPUART1);
lpuart_event.tx_busy = 0;
}
uint8_t lpuart_start_tx(uint8_t* buff, uint16_t len ){
if(!lpuart_event.tx_busy){
lpuart_event.tx_busy = 1;
if(len < SIZE_TX_BUFF){
lpuart_event.start_tx = 1;
tempTxBuf = buff;
txLen = len;
}else{
/* lpuart_event.start_tx = 0;
lpuart_event.buff_full = 1;*/
return 0;
}
return 1;
}else{
return 0;
}
}
void lpuart_transmit(){
memcpy(txBuf, tempTxBuf, txLen);
setTxDataLengthDMA(txLen);
LL_LPUART_EnableDMAReq_TX(LPUART1);
LL_LPUART_EnableDirectionTx(LPUART1);
LL_LPUART_EnableIT_TC(LPUART1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
}
void lpuart_finished_tx(){
LL_LPUART_DisableIT_TC(LPUART1);
LL_LPUART_DisableDirectionTx(LPUART1);
LL_DMA_DisableIT_TC(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableIT_TE(DMA1, LL_DMA_CHANNEL_1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
lpuart_event.txtc = 0;
lpuart_event.dmatxtc = 0;
lpuart_event.start_tx = 0;
lpuart_event.tx_busy = 0;
}
void setTxDataLengthDMA(uint16_t len){
LL_LPUART_DisableDirectionTx(LPUART1);
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
/* Clear all flags */
LL_DMA_ClearFlag_TC1(DMA1);
LL_DMA_ClearFlag_TE1(DMA1);
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, len);
}
void check_rx_dma_buff(){
static uint16_t old_len = SIZE_DMA_RX_BUFF;
uint16_t current_len = LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
if(old_len != current_len ){
if(current_len > 0){
lpuart_event.rx_read = 1;
}
}
old_len = current_len;
}
static uint16_t old_pos = 0;
uint16_t pos = 0;
void lpuart_rx(){
lpuart_event.ext_rxBusyFlag = 1;
if(lpuart_event.dmarxtc){
lpuart_event.dmarxtc = 0;
}
if(lpuart_event.rx_read){
lpuart_event.rx_read = 0;
}
pos = (uint16_t)SIZE_DMA_RX_BUFF - LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_2);
if(pos > SIZE_DMA_RX_BUFF ){
pos = SIZE_DMA_RX_BUFF;
}
if(pos != old_pos /* || (pos == 0 && old_pos == 0)*/){
if (pos > old_pos) {
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[old_pos],(pos - old_pos));
}else{
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[old_pos],((uint16_t)SIZE_DMA_RX_BUFF - old_pos));
if(pos > 0){
RingBuffer_writeMeasBlock(&lpuart_RX_ring_buff,&rxDMA_Buf[0],pos);
}
}
}
old_pos = pos;
lpuart_event.ext_rxBusyFlag = 0;
}
t_fsm_row rowInit = {INIT,ev_no_event, ev_no_event, lpuart_init, no_action, READY };
t_fsm_row rowReady = {READY,ev_start_tx, ev_no_event, lpuart_transmit, no_action, BUSY };
t_fsm_row rowBusy = {BUSY,ev_dmatxtc, ev_txtc, lpuart_finished_tx, no_action, READY};
t_fsm_table lpuart_fsm_table = {INIT,INIT, {}};
void fsm_table_init(){
lpuart_fsm_table.current_state = INIT;
lpuart_fsm_table.stt_row[0] = rowInit;
lpuart_fsm_table.stt_row[1] = rowReady;
lpuart_fsm_table.stt_row[2] = rowBusy;
lpuart_event.is_fsm_table_init = 1;
lpuart_fsm_table.number_of_rows = 3;
}
void lpuar_tx_fsm(){
uint8_t ev = 0;
for(uint16_t rowIndex = 0; rowIndex < lpuart_fsm_table.number_of_rows; rowIndex++){
if(lpuart_fsm_table.current_state == lpuart_fsm_table.stt_row[rowIndex].present_state){
ev = lpuart_fsm_table.stt_row[rowIndex].event1() && lpuart_fsm_table.stt_row[rowIndex].event2();
if(ev){
lpuart_fsm_table.stt_row[rowIndex].action1();
lpuart_fsm_table.stt_row[rowIndex].action2();
lpuart_fsm_table.current_state = lpuart_fsm_table.stt_row[rowIndex].next_state;
lpuart_fsm_table.previous_state = lpuart_fsm_table.stt_row[rowIndex].present_state;
}
}
}
}
void lpuar_read_task(){
check_rx_dma_buff();
if(ev_rx_read()){
lpuart_rx();
}
}
void lpuart_task(){
if(!lpuart_event.is_fsm_table_init){
fsm_table_init();
}
//else{
lpuar_tx_fsm();
lpuar_read_task();
//}
}
void LPUART_TX_TC_ISR_CALLBACK(void){
lpuart_event.txtc = 1;
LL_LPUART_ClearFlag_TC(LPUART1);
}
void LPUART_DMA_TX_TC_CALLBACK(void){
lpuart_event.dmatxtc = 1;
LL_DMA_ClearFlag_TC1(DMA1);
}
void LPUART_DMA_RX_TC_CALLBACK(void){
if(LL_DMA_IsActiveFlag_TC2(DMA1)){
LL_DMA_ClearFlag_TC2(DMA1);
lpuart_event.dmarxtc = 1;
lpuart_rx();
}
if(LL_DMA_IsActiveFlag_TE2(DMA1)){
LL_DMA_ClearFlag_TE2(DMA1);
}
}
Intrrupt routine file stm32g4xx_it.c:
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32g4xx_it.h"
#include "lpuart.h"
extern _func_clbck lpuart_tx_tc_isr_clback;
//_func_clbck lpuart_rx_rne_isr_clback = LPUART_RX_RXNE_ISR_CALLBACK;
extern _func_clbck lpuart_dma_tx_tc_isr_clback;
extern _func_clbck lpuart_dma_rx_tc_isr_clback;
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
void DMA1_Channel2_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Channel2_IRQn 0 */
lpuart_dma_rx_tc_isr_clback();
//LPUART_DMA_RX_TC_CALLBACK();
/* USER CODE END DMA1_Channel2_IRQn 0 */
/* USER CODE BEGIN DMA1_Channel2_IRQn 1 */
/* USER CODE END DMA1_Channel2_IRQn 1 */
}
Some of the code I have ommitted here. I am sure that I have not fully understood how function pointers work. Could you please give me suggestions or a solution.
I am using:
language: C11
Compiler/build tools: GNU tools for STM32 (7-2018-q2-update)
IDE: STM32CubeIDE
Please let me know if you require more info. Thanks in advance.
As per #Lundin's suggestion, I have put a watchpoint on lpuart_dma_rx_tc_isr_clback function pointer variable. It exposed the out of index bug in my code. The bug is inside while loop in main.c.
rxIndex = RingBuffer_available(&lpuart_RX_ring_buff);
for(i = rxOldIndex ; i < (rxIndex+rxOldIndex) ; i++ ){
rxBuff[i] = RingBuffer_readMeas(&lpuart_RX_ring_buff);
....
}
It was also pointed out that function pointer variable shouldn't be in flash.
I have a Nordic nRF52840DK board that needs to be connected to an LSM6DSL accelerometer. I am using the Zephyr RTOS and the sample code from Zephyr is shown below:
/*
* Copyright (c) 2018 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <device.h>
#include <drivers/sensor.h>
#include <stdio.h>
#include <sys/util.h>
static inline float out_ev(struct sensor_value *val)
{
return (val->val1 + (float)val->val2 / 1000000);
}
static int print_samples;
static int lsm6dsl_trig_cnt;
static struct sensor_value accel_x_out, accel_y_out, accel_z_out;
static struct sensor_value gyro_x_out, gyro_y_out, gyro_z_out;
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
static struct sensor_value magn_x_out, magn_y_out, magn_z_out;
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
static struct sensor_value press_out, temp_out;
#endif
#ifdef CONFIG_LSM6DSL_TRIGGER
static void lsm6dsl_trigger_handler(const struct device *dev,
struct sensor_trigger *trig)
{
static struct sensor_value accel_x, accel_y, accel_z;
static struct sensor_value gyro_x, gyro_y, gyro_z;
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
static struct sensor_value magn_x, magn_y, magn_z;
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
static struct sensor_value press, temp;
#endif
lsm6dsl_trig_cnt++;
sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ);
sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &accel_x);
sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &accel_y);
sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &accel_z);
/* lsm6dsl gyro */
sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ);
sensor_channel_get(dev, SENSOR_CHAN_GYRO_X, &gyro_x);
sensor_channel_get(dev, SENSOR_CHAN_GYRO_Y, &gyro_y);
sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &gyro_z);
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
/* lsm6dsl external magn */
sensor_sample_fetch_chan(dev, SENSOR_CHAN_MAGN_XYZ);
sensor_channel_get(dev, SENSOR_CHAN_MAGN_X, &magn_x);
sensor_channel_get(dev, SENSOR_CHAN_MAGN_Y, &magn_y);
sensor_channel_get(dev, SENSOR_CHAN_MAGN_Z, &magn_z);
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
/* lsm6dsl external press/temp */
sensor_sample_fetch_chan(dev, SENSOR_CHAN_PRESS);
sensor_channel_get(dev, SENSOR_CHAN_PRESS, &press);
sensor_sample_fetch_chan(dev, SENSOR_CHAN_AMBIENT_TEMP);
sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
#endif
if (print_samples) {
print_samples = 0;
accel_x_out = accel_x;
accel_y_out = accel_y;
accel_z_out = accel_z;
gyro_x_out = gyro_x;
gyro_y_out = gyro_y;
gyro_z_out = gyro_z;
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
magn_x_out = magn_x;
magn_y_out = magn_y;
magn_z_out = magn_z;
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
press_out = press;
temp_out = temp;
#endif
}
}
#endif
void main(void)
{
int cnt = 0;
char out_str[64];
struct sensor_value odr_attr;
const struct device *lsm6dsl_dev = device_get_binding(DT_LABEL(DT_INST(0, st_lsm6dsl)));
if (lsm6dsl_dev == NULL) {
printk("Could not get LSM6DSL device\n");
return;
}
/* set accel/gyro sampling frequency to 104 Hz */
odr_attr.val1 = 104;
odr_attr.val2 = 0;
if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_ACCEL_XYZ,
SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {
printk("Cannot set sampling frequency for accelerometer.\n");
return;
}
if (sensor_attr_set(lsm6dsl_dev, SENSOR_CHAN_GYRO_XYZ,
SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {
printk("Cannot set sampling frequency for gyro.\n");
return;
}
#ifdef CONFIG_LSM6DSL_TRIGGER
struct sensor_trigger trig;
trig.type = SENSOR_TRIG_DATA_READY;
trig.chan = SENSOR_CHAN_ACCEL_XYZ;
if (sensor_trigger_set(lsm6dsl_dev, &trig, lsm6dsl_trigger_handler) != 0) {
printk("Could not set sensor type and channel\n");
return;
}
#endif
if (sensor_sample_fetch(lsm6dsl_dev) < 0) {
printk("Sensor sample update error\n");
return;
}
while (1) {
/* Erase previous */
printk("\0033\014");
printf("LSM6DSL sensor samples:\n\n");
/* lsm6dsl accel */
sprintf(out_str, "accel x:%f ms/2 y:%f ms/2 z:%f ms/2",
out_ev(&accel_x_out),
out_ev(&accel_y_out),
out_ev(&accel_z_out));
printk("%s\n", out_str);
/* lsm6dsl gyro */
sprintf(out_str, "gyro x:%f dps y:%f dps z:%f dps",
out_ev(&gyro_x_out),
out_ev(&gyro_y_out),
out_ev(&gyro_z_out));
printk("%s\n", out_str);
#if defined(CONFIG_LSM6DSL_EXT0_LIS2MDL)
/* lsm6dsl external magn */
sprintf(out_str, "magn x:%f gauss y:%f gauss z:%f gauss",
out_ev(&magn_x_out),
out_ev(&magn_y_out),
out_ev(&magn_z_out));
printk("%s\n", out_str);
#endif
#if defined(CONFIG_LSM6DSL_EXT0_LPS22HB)
/* lsm6dsl external press/temp */
sprintf(out_str, "press: %f kPa - temp: %f deg",
out_ev(&press_out), out_ev(&temp_out));
printk("%s\n", out_str);
#endif
printk("loop:%d trig_cnt:%d\n\n", ++cnt, lsm6dsl_trig_cnt);
print_samples = 1;
k_sleep(K_MSEC(2000));
}
}
From my previous experience working with Arduino, you need to define the pins before the main function, but there isn't any definition on pins in this code example. So my question is: How does the board know which pins to use when connected to the sensor?
Thanks in advance!
In embedded C (bare metal and some RTOS), the developer is expected to know what is connected where and which registers to use to access the connected hardware by driving the right pins.
In the specific case of Zephyr (as well as Das U-Boot and Linux on some architectures), the system configuration (among other things pins, but not only) is described by a device-tree. It is a "a data structure for describing hardware", which allows the firmware code to become independent of the actual hardware.
The device-tree will describe many things, the most important being:
the device's memory map
the list of CPUs and their properties (frequency, caches, ...)
the peripherals, as well as their configuration
Zephyr does have a very good introduction to device-tree.
In the code you posted, Zephyr does retrieve the device information from the device-tree when executing the following line:
const struct device *lsm6dsl_dev = device_get_binding(DT_LABEL(DT_INST(0, st_lsm6dsl)));
I have a NUCLEO STM32L152RE. I want to use the low power features of this board and wrote this easy example. I use CubeMX to configure the board.
I want to wake up every 3 minutes, but 6 minutes later the system freezes.
/* Private variables */
ADC_HandleTypeDef hadc;
I2C_HandleTypeDef hi2c1;
RTC_HandleTypeDef hrtc;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim11;
UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
UART_HandleTypeDef huart3;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_ADC_Init(void);
static void MX_I2C1_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM11_Init(void);
static void MX_USART3_UART_Init(void);
uint8_t data[]={3,3};
uint8_t data2[]={2,3};
uint8_t data3[]={5,6};
uint8_t dataS4[]={4,4};
uint8_t dataS5[]={5,5};
uint8_t dataS6[]={6,6};
uint8_t dataS7[]={9,9};
uint8_t dataD[]={7,7};
uint8_t dataS1[]={1,1};
uint8_t command1[]="default;"; //
uint8_t command2[]="up;"; // THE SYSTEM UP
int i = 0;
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
HAL_PWR_EnableBkUpAccess(); //enable PWR backup domain access (RTC,BKReg)
__HAL_RCC_RTC_ENABLE(); //Enable RTC. not created by cube because the RTC can run.
/* USER CODE END 1 */
/* MCU Configuration------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_RTC_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_ADC_Init();
MX_I2C1_Init();
MX_TIM3_Init();
MX_TIM11_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
HAL_UART_Transmit(&huart2,data,2,1000);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// here i have code.......
HAL_Delay(500);
HAL_UART_Transmit(&huart2,dataS7,2,1000);
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON,PWR_STOPENTRY_WFI); // stop mode
}
}
RTC Initialization
/* RTC init function */
static void MX_RTC_Init(void)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
RTC_AlarmTypeDef sAlarm;
/**Initialize RTC Only */
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
/**Initialize RTC and set the Time and Date */
sTime.Hours = 0x0;
sTime.Minutes = 0x0;
sTime.Seconds = 0x0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x1;
sDate.Year = 0x0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
/**Enable the Alarm A */
sAlarm.AlarmTime.Hours = 0x0;
sAlarm.AlarmTime.Minutes = 0x3;
sAlarm.AlarmTime.Seconds = 0x0;
sAlarm.AlarmTime.SubSeconds = 0x0;
sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
sAlarm.AlarmMask =RTC_ALARMMASK_NONE;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 0x1;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
}
Here I have the code for handling the interrupt:
/* interrupt callback */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc){
RTC_AlarmTypeDef sAlarm;
HAL_RTC_GetAlarm(hrtc,&sAlarm,RTC_ALARM_A,FORMAT_BIN);
if(sAlarm.AlarmTime.Minutes>58){
sAlarm.AlarmTime.Minutes=0;
}else{
sAlarm.AlarmTime.Minutes=sAlarm.AlarmTime.Minutes+1;
}
while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK){}
SystemClock_Config(); // UP THE SYSTEM
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); //TAGGLE THE LED
HAL_UART_Transmit(&huart2,data3,2,1000);
HAL_UART_Transmit(&huart1,command2,sizeof(command2),1000);
}
I want that every 3 minutes the system wakes up and later goes in stop mode, but the system doesn't work. After 60 minutes the system doesn't do anything. Can you help me?