I am using an STM32G431CB (and the HAL) to record ADC data data using DMA, control/read GPIOs, communicate via I2C and USB CDC (virtual comm port), and use timers. I have verified that each of these peripherals work correctly individually both on a dev board (NUCLEO-G431KB) and on my custom board with the 48 pin version of the same chip (STM32G431CB).
However, the problem that I am running into is that the program will occasionally jump to an instruction at address 0x1fff4be0. This is in system memory. After inspecting disassembly, I don't see any instruction that would cause it to branch here. In different versions of this program with one or few of the peripherals running, this jump has happened when calling different HAL functions including:
HAL_GPIO_ReadPin
HAL_GPIO_WritePin
HAL_I2C_Master_Transmit
HAL_ADC_Start_DMA
I don't think that there is any correlation between the function called and the jump to system memory.
What can cause the STM32 to do this? I am trying to use PB8-BOOT0 as a GPIO output. When I leave PB8-BOOT0 unconfigured (reset state), I do not run into this issue.
main.c:
#include "main.h"
#include "usb_device.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdint.h>
#include "mymain.h"
#include "usbd_cdc_if.h"
/* 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 ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
I2C_HandleTypeDef hi2c3;
TIM_HandleTypeDef htim6;
TIM_HandleTypeDef htim7;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_DMA_Init(void);
static void MX_I2C3_Init(void);
static void MX_TIM7_Init(void);
static void MX_TIM6_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint16_t ADC_result[4]; // ADC results: {TEMP_SENSOR, AC_CHG, R_SLIDER, L_SLIDER}
uint8_t I2Cdata;
uint8_t USB_tx_buffer[24];
struct SB_data SB1;
struct SB_data SB2;
uint16_t GPIO_data = 0x00c0;
/* 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();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_DMA_Init();
MX_I2C3_Init();
MX_USB_Device_Init();
MX_TIM7_Init();
MX_TIM6_Init();
/* USER CODE BEGIN 2 */
HAL_DMA_Init(&hdma_adc1);
TPS55288Q1_Init();
// GPIO initial states
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); // Initialize USB 3 hub in reset until tablet supplies power on TAB_DCOUT->VBUS_DET3V3 (PA2)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET); // Initialize 5V, 3.3V, 2.5V, 1.2V supplies off (net Enable_Power)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET); // Initialize L mouse off
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET); // Enable EN_EXT_USB_PWR by default
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET); // DISABLE_CHG1
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET); // DISABLE_CHG2
// BEGIN TESTING ONLY //
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
// END TESTING ONLY //
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// ADC DMA Start
//HAL_ADC_Start_DMA(&hadc1, (uint32_t*) ADC_result, 4);
// Log GPIO data
log_GPIO_data();
/* USER CODE END WHILE */
/* 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};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** 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_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 12;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV4;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
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_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* #brief ADC1 Initialization Function
* #param None
* #retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.GainCompensation = 0;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 4;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_2;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR_ADC1;
sConfig.Rank = ADC_REGULAR_RANK_4;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* #brief I2C3 Initialization Function
* #param None
* #retval None
*/
static void MX_I2C3_Init(void)
{
/* USER CODE BEGIN I2C3_Init 0 */
/* USER CODE END I2C3_Init 0 */
/* USER CODE BEGIN I2C3_Init 1 */
/* USER CODE END I2C3_Init 1 */
hi2c3.Instance = I2C3;
hi2c3.Init.Timing = 0x00303D5B;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C3_Init 2 */
/* USER CODE END I2C3_Init 2 */
}
/**
* #brief TIM6 Initialization Function
* #param None
* #retval None
*/
static void MX_TIM6_Init(void)
{
/* USER CODE BEGIN TIM6_Init 0 */
/* USER CODE END TIM6_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM6_Init 1 */
/* USER CODE END TIM6_Init 1 */
htim6.Instance = TIM6;
htim6.Init.Prescaler = 1600-1;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP;
htim6.Init.Period = 19999;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM6_Init 2 */
/* USER CODE END TIM6_Init 2 */
}
/**
* #brief TIM7 Initialization Function
* #param None
* #retval None
*/
static void MX_TIM7_Init(void)
{
/* USER CODE BEGIN TIM7_Init 0 */
/* USER CODE END TIM7_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM7_Init 1 */
/* USER CODE END TIM7_Init 1 */
htim7.Instance = TIM7;
htim7.Init.Prescaler = 1600-1;
htim7.Init.CounterMode = TIM_COUNTERMODE_UP;
htim7.Init.Period = 121;
htim7.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim7) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim7, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM7_Init 2 */
/* USER CODE END TIM7_Init 2 */
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMAMUX1_CLK_ENABLE();
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
/**
* #brief GPIO Initialization Function
* #param None
* #retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4|GPIO_PIN_10, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8, GPIO_PIN_RESET);
/*Configure GPIO pins : PA4 PA10 */
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB2 PB11 PB12 PB8 */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
// Initializes TPS55288Q1 buck-boost converters by configuring external voltage divider, resetting error flags, and disabling output
void TPS55288Q1_Init() {
I2Cdata = 0b10000011;
HAL_I2C_Mem_Write(&hi2c3, TPS55288Q1_TAB_DCIN_DEV_ADDR<<1, TPS55288Q1_VOUT_FS_ADDR, 1, &I2Cdata, 1, 2); // Use external voltage divider
HAL_I2C_Mem_Write(&hi2c3, TPS55288Q1_12V_DEV_ADDR<<1, TPS55288Q1_VOUT_FS_ADDR, 1, &I2Cdata, 1, 2);
HAL_I2C_Mem_Read(&hi2c3, TPS55288Q1_TAB_DCIN_DEV_ADDR<<1, TPS55288Q1_STATUS_R, 1, &I2Cdata, 1, 2); // Read and reset error flags
HAL_I2C_Mem_Read(&hi2c3, TPS55288Q1_12V_DEV_ADDR<<1, TPS55288Q1_STATUS_R, 1, &I2Cdata, 1, 2);
I2Cdata = 0b00100000; // ~OE, all else default
HAL_I2C_Mem_Write(&hi2c3, TPS55288Q1_TAB_DCIN_DEV_ADDR<<1, TPS55288Q1_MODE_R_ADDR, 1, &I2Cdata, 1, 2);
HAL_I2C_Mem_Write(&hi2c3, TPS55288Q1_12V_DEV_ADDR<<1, TPS55288Q1_MODE_R_ADDR, 1, &I2Cdata, 1, 2);
}
// switches the channel being read on ADC1
void ADC1_Select_Channel(uint32_t channel) {
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = channel;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Error_Handler();
}
}
// reads GPIO inputs that will be transmitted to the tablet
// {DISABLE_CHG2, DISABLE_CHG1, ~BATID2, ~BATID1, RB2, RB1, LB2, LB1}
void log_GPIO_data() {
GPIO_data &= 0xffc0; // clear bottom 6 bits
GPIO_data |= HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) | (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7) << 1) |
(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) << 2) | (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) << 3) |
(!HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) << 4) | (!HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_1) << 5);
}
void set_bit(uint16_t* data, uint8_t bit_pos, uint8_t value) {
if (value) {
*data |= 1<<bit_pos;
} else {
*data &= ~(1<<bit_pos);
}
}
// Returns 1 if either battery is inserted and not fully discharged or if AC_CHG_Det is 1. Indicates active power source
uint8_t PWRsource_det() {
return (bat1_inserted() && (SB1.status[0] & 0x10)) || (bat2_inserted() && (SB2.status[0] & 0x10)) || (GPIO_data & 0x0100);
}
// Returns 1 if Smart Battery 1 is inserted, 0 otherwise
uint8_t bat1_inserted() { // internal pull down resistor on smart battery when detected. Pin is low when battery is inserted
return GPIO_data & (1<<4);
}
// Returns 1 if Smart Battery 2 is inserted, 0 otherwise
uint8_t bat2_inserted() { // internal pull down resistor on smart battery when detected. Pin is low when battery is inserted
return GPIO_data & (1<<5);
}
// loads the USB CDC transmission buffer. Multi-byte data fields are Little Endian. Ends in \n\r.
void load_USB_TX_buffer(uint8_t* TX_buffer, struct SB_data* bat1, struct SB_data* bat2, uint16_t* ADC_readings, uint16_t GPIO_inputs, uint16_t temperature) {
TX_buffer[0] = bat1->status[0];
TX_buffer[1] = bat1->status[1];
TX_buffer[2] = bat1->timetoempty[0];
TX_buffer[3] = bat1->timetoempty[1];
TX_buffer[4] = bat1->voltage[0];
TX_buffer[5] = bat1->voltage[1];
TX_buffer[6] = bat1->chgpercent;
TX_buffer[7] = bat2->status[0];
TX_buffer[8] = bat2->status[1];
TX_buffer[9] = bat2->timetoempty[0];
TX_buffer[10] = bat2->timetoempty[1];
TX_buffer[11] = bat2->voltage[0];
TX_buffer[12] = bat2->voltage[1];
TX_buffer[13] = bat2->chgpercent;
TX_buffer[14] = (uint8_t) (ADC_readings[1] >> 8); // Right slider
TX_buffer[15] = (uint8_t) ADC_readings[1];
TX_buffer[16] = (uint8_t) (ADC_readings[0] >> 8); // Left Slider
TX_buffer[17] = (uint8_t) ADC_readings[0];
TX_buffer[18] = (uint8_t) (temperature >> 8); // Temperature sensor
TX_buffer[19] = (uint8_t) temperature;
TX_buffer[20] = (uint8_t) (GPIO_inputs & 0xff);
TX_buffer[21] = (uint8_t) ((GPIO_inputs >> 8) & 0xff);
TX_buffer[22] = (uint8_t) '\n';
TX_buffer[23] = (uint8_t) '\r';
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) {
if (htim == &htim6) { // USB RX Comms 2s timeout
HAL_TIM_Base_Stop_IT(&htim7); // Stop USB TX
HAL_TIM_Base_Stop_IT(&htim6);
// disable 12V and TAB_DCIN
uint8_t data = 0b00100000; // ~OE, all else default
HAL_I2C_Mem_Write(&hi2c3, TPS55288Q1_TAB_DCIN_DEV_ADDR<<1, TPS55288Q1_MODE_R_ADDR, 1, &data, 1, 10);
data = 0b00100100; // ~OE, address=0x75, all else default
HAL_I2C_Mem_Write(&hi2c3, TPS55288Q1_12V_DEV_ADDR<<1, TPS55288Q1_MODE_R_ADDR, 1, &data, 1, 10);
// disable 5V, 3.3V, 2.5V, 1.2V supplies (net Enable_Power)
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET);
} else if (htim == &htim7) { // USB TX call (82Hz)
uint16_t temperature = __HAL_ADC_CALC_TEMPERATURE(3300, ADC_result[3], ADC_RESOLUTION_12B);
load_USB_TX_buffer(USB_tx_buffer, (struct SB_data*) &SB1, (struct SB_data*) &SB2, (uint16_t*) ADC_result, GPIO_data, temperature);
CDC_Transmit_FS(USB_tx_buffer, sizeof(USB_tx_buffer));
/* ** UART DEBUG **
uint8_t usart_d[] = "SRS\n\r";
HAL_UART_Transmit(&huart2, usart_d, sizeof(usart_d), 2);
*/
}
}
/* 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 */
}
#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 */
Your microcontroller is executing the embedded bootloader.
Depending on the micro that can be caused by one or more of the following:
Obtion byte settings
BOOT0 pin
Content of the first word of flash during BOR.
Option byte are loaded only on BOR if an update is not explicited called through OBL_LAUNCH. Flash empty flag (the last point) is also only evaluated during BOR. No update is possible without BOR. You can exit bootloader with an approriate command via bootloader interfaces.
Probably due to the fact you are using BOOT0 as a GPIO (unless it is a specific feature of the STM32G4, I know only H7 and L4).
I think if a reset occurs for whatever reason , and the signal is at the wrong state, you will end up booting on System Flash.
I have to measure adc value using internal reference voltage in STM32L422. According to datasheet STM32L422 internal reference voltage is 1.2 V. I enabled internal Vref from CubeMX.
Analog input is 1V but I get 0.58 V. what is the problem here anyone ?
STM32L422 datasheet says that internal Vref = 1.2 V. When I measured Vref pin, it was 0.53 V.
What is wrong over here ?
For 1 V input which is obtained using 20K, 10K voltage divider, for 3V, digital and analog values obtained are are follows:
Digital: 1983, Analog value: 0.581099
#define VREFINT_ADDR 0x1FFF75AA // VREF voltage
#define VREFINT (*((uint16_t *) VREFINT_ADDR))
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();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_TIM6_Init();
MX_RTC_Init();
/* USER CODE BEGIN 2 */
printf("System Booting On! \n");
printf("VREFINT: %ud\n", VREFINT);
printf("ADC Calibration! \n");
while(HAL_ADCEx_Calibration_Start(&hadc1,0) != HAL_OK);
printf("Battery Voltage Check ...\n");
HAL_Delay(100); // 1000ms OK => 100ms OK
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,100);
ADC_Val=HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
float Result = (float)((1.200 * ADC_Val) / 4095);
printf("****************************************************************\n");
printf("Digital: %d, Analog value : %f\r\n", ADC_Val, Result);
printf("****************************************************************\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
;
}
/* USER CODE END 3 */
}
void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV8;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_92CYCLES_5;
// sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
STM32 ADC works a bit different way than you think and the Vrefint name is a bit confusing. Always read the Reference Manual.
Vrefint is not the reference voltage for ADC. It is simply connected one of the channels. When you measure this voltage you can know your Vref for ADC (in your case it is Vdda) So the formula you use is wrong.
STM32L422 datasheet says that internal Vref = 1.2 V
Do not read the datasheet only Reference Manual
Then you need to measure your Vref (Vdda) and rthen you can measure your voltage on the pin.
In a STM32G4, I was able to setup the DAC DMA such that I could use a regular variable (ie. a uint8_t array). However, when I tried porting my code over to an H723, the DAC DMA would not work unless it's with a constant variable (ie. a const uint8_t array) that is set before runtime. My application requires runtime changes to the array. A pointer initialization of the array does not seem to work. I was wondering if there is a way to remedy this? Am I stuck with the constant variable? Thank you!
EDIT1: Current Setup of DAC DMA and TIMER
static void MX_DAC1_Init(void){
DAC_ChannelConfTypeDef sConfig = {0};
hdac1.Instance = DAC1;
if (HAL_DAC_Init(&hdac1) != HAL_OK){
Error_Handler();
}
sConfig.DAC_SampleAndHold = DAC_SAMPLEANDHOLD_DISABLE;
sConfig.DAC_Trigger = DAC_TRIGGER_T15_TRGO;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_DISABLE;
sConfig.DAC_ConnectOnChipPeripheral = DAC_CHIPCONNECT_ENABLE;
sConfig.DAC_UserTrimming = DAC_TRIMMING_FACTORY;
if (HAL_DAC_ConfigChannel(&hdac1, &sConfig, DAC_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
}
Timer15 Config:
static void MX_TIM15_Init(void)
{ TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim15.Instance = TIM15;
htim15.Init.Prescaler = 55-1;
htim15.Init.CounterMode = TIM_COUNTERMODE_UP;
htim15.Init.Period = 10-1;
htim15.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim15.Init.RepetitionCounter = 0;
htim15.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim15) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim15, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim15, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
DMA Config:
static void MX_DMA_Init(void){
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* DMAMUX1_OVR_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMAMUX1_OVR_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMAMUX1_OVR_IRQn);
}
in the main function:
int main(void){
MX_DAC1_Init();
MX_TIM15_Init();
MX_OPAMP2_Init();
/* USER CODE BEGIN 2 */
set_sine(dac_data1, NUM_DAC_POINTS) //Set a max amplitude uniformly over number of points, dac_data is initialized as uint8_t dac_data1[NUM_DAC_POINTS];
HAL_TIM_Base_Start(&htim15); //Start the timer for DAC DMA Transfer
HAL_DAC_Init(&hdac1);
(HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_2, (uint32_t *)dac_data1, NUM_DAC_POINTS, DAC_ALIGN_8B_R);
}
This setup does not work, but just by initialzing dac_data1 as const uint8_t and predefining it, the DMA works.
Ok, Thanks to Tom V for the insight on the Different Memory Banks. In my case, dac_data1 is placed on RAM, also known as DTCMRAM on the reference manual. DTCMRAM is not accessible to DMA but is chosen to be the default memory location for runtime operations on the H7. A modification in the linker files (In my case, both ..._FLASH.ld and ..._RAM.ld) were needed. I changed the .bss, .data and ._user_heap_stack memory location from RAM to RAM_D1. This was taken directly from: https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices
I'm attempting to get two ADC's to simultaneously sample on a STM32H743. However, I cannot seem to read the values from ADC2 correctly. From my understanding, when running in dual simultaneous mode, the data from the two ADC conversions are written to the buffer as a 32 bit word. I have set up the STM32CubeMonitor to read the first 16 bits of the buffer and the second 16 bits and plot them. However, despite having different inputs to each adc (one square wave, and one triangle) I only see the input on ADC1. The values of ADC2 reflect what is on the input of ADC1. I'm not entirely sure what I'm doing wrong as I've tried just about every combination of settings I can think of. I would appreciate any insight.
I have tried both the NUCLEO board and the EVAL board and have not seen much success. I'm using STM32CubeIDE to configure everything and STM32CubeMonitor to monitor the values read.
Here are the configuration of both ADCs.
ADC1/ADC2
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc1.Init.Resolution = ADC_RESOLUTION_16B;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure the ADC multi-mode
*/
multimode.Mode = ADC_DUALMODE_REGSIMULT;
multimode.DualModeData = ADC_DUALMODEDATAFORMAT_32_10_BITS;
multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_1CYCLE;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_19;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* #brief ADC2 Initialization Function
* #param None
* #retval None
*/
static void MX_ADC2_Init(void)
{
/* USER CODE BEGIN ADC2_Init 0 */
/* USER CODE END ADC2_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC2_Init 1 */
/* USER CODE END ADC2_Init 1 */
/** Common config
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc2.Init.Resolution = ADC_RESOLUTION_16B;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc2.Init.LowPowerAutoWait = DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DMA_CIRCULAR;
hadc2.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc2.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
hadc2.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_18;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
/* USER CODE END ADC2_Init 2 */
}
you need these global variables:
ALIGN_32BYTES(__IO uint32_t ADCDualConvertedValues[4]); //array size of your adc ranks
/* dual values */
uint32_t poz_0_dual = 0; //Variable holding ADC1 ADC2 values
uint32_t poz_1_dual = 0; //Variable holding ADC1 ADC2 values
uint32_t poz_2_dual = 0; //Variable holding ADC1 ADC2 values
uint32_t poz_3_dual = 0; //Variable holding ADC1 ADC2 values
/* single VALUES */
uint16_t poz_0_a = 0;
uint16_t poz_0_b = 0;
uint16_t poz_1_a = 0;
uint16_t poz_1_b = 0;
uint16_t poz_2_a = 0;
uint16_t poz_2_b = 0;
uint16_t poz_3_a = 0;
uint16_t poz_3_b = 0;
you need to add following code to your int main(void)
if(HAL_ADC_Start(&hadc2) != HAL_OK){Error_Handler();}
if(HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)ADCDualConvertedValues, 4) != HAL_OK){Error_Handler();} //Must use multimode!
In your while(1)
/* passing values */
poz_0_dual = ADCDualConvertedValues[0];
poz_1_dual = ADCDualConvertedValues[1];
poz_2_dual = ADCDualConvertedValues[2];
poz_3_dual = ADCDualConvertedValues[3];
/* shifting 32 to 16 */
poz_0_a = (uint16_t) poz_0_dual;
poz_0_b = (uint16_t) (poz_0_dual >> 16);
poz_1_a = (uint16_t) poz_1_dual;
poz_1_b = (uint16_t) (poz_1_dual >> 16);
poz_2_a = (uint16_t) poz_2_dual;
poz_2_b = (uint16_t) (poz_2_dual >> 16);
poz_3_a = (uint16_t) poz_3_dual;
poz_3_b = (uint16_t) (poz_3_dual >> 16);
I hope it helps to you. Don't forget multimode.DualModeData = ADC_DUALMODEDATAFORMAT_32_10_BITS; in your adc.c
mfG
fejes
So I wanted to read out multiple channels from adc3 on my stm32f7 discovery. I have been able to read out one channel and set up for multiple ones, but I can't figure out how to read out per channel. I wanted to read them out by interrupt so I set the adc up like this:
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
hadc3.Init.ScanConvMode = ENABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
hadc3.Init.ContinuousConvMode = ENABLE; /* Continuous mode enabled to have continuous conversion */
hadc3.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */
hadc3.Init.NbrOfDiscConversion = 0;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Conversion start trigged at each external event */
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = 2;
hadc3.Init.DMAContinuousRequests = DISABLE;
hadc3.Init.EOCSelection = DISABLE;
if (HAL_ADC_Init(&hadc3) != HAL_OK)
{
/* ADC initialization Error */
Error_Handler();
}
/*##-2- Configure ADC regular channel ######################################*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
Error_Handler();
}
/*##-2- Configure ADC regular channel ######################################*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 2;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
Error_Handler();
}
/*##-3- Start the conversion process #######################################*/
if(HAL_ADC_Start_IT(&hadc3) != HAL_OK)
{
/* Start Conversation Error */
Error_Handler();
}
and then I have a callback where it will go when end of conversion, here I wanted to read the data out but I don't know how to read out per channel.
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
/* Get the converted value of regular channel */
ADC3ConvertedValue[0] = HAL_ADC_GetValue(AdcHandle);
ADC3ConvertedValue[1] = HAL_ADC_GetValue(AdcHandle);
char disp[50];
sprintf(disp, "%d%%", ADC3ConvertedValue[0]);
BSP_LCD_DisplayStringAtLine(1, (uint8_t*) disp);
char disp1[50];
sprintf(disp1, "%d%%", ADC3ConvertedValue[1]);
BSP_LCD_DisplayStringAtLine(2, (uint8_t*) disp1);
}
can anyone help me with reading this out. I don't want to use the DMA because it conflicts with the LCD.