I'm trying to use the UART3 in NUCLEO-F746ZG with TrueStudio.
USART3 connected to ST-LINK to support the virtual COM port, but it didn't work now. I don't have oscilloscope and I really want to see the print message through hyper terminal like a realterm.
I searched this issue and found that many users were having a hard time.
Finally, I found the solution for UART example which is in STM32CubMX from the following web site. If I copy the syscall.c, then it works fine in UART example.
https://community.st.com/s/question/0D50X00009XkXDcSAN/problem-with-uart-example-on-nucleof746zg
The following is UART example code from STM32CubeMX.
Directory : STM32Cube_FW_F7_V1.15.0\Projects\STM32F746ZG-Nucleo\Examples\UART\UART_Printf.
int main(void)
{
.....................
UartHandle.Instance = USARTx;
UartHandle.Init.BaudRate = 9600;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&UartHandle) != HAL_OK)
{
Error_Handler();
}
}
However, I generated the code using STM32CubeMX. I only made use of USART3 and confirmed that there is syscall.c in it. But nevertheless I can't see the print message. If anyone solved this problem, I would appreciate it if they shared it.
The following is the code I generated using STM32CubeMX.
int main(void)
{
HAL_Init();
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
...
}
static void MX_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 9600;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
huart3.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart3.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
}
Related
The goal is to read multiple ADC channels by polling. It does not need to be fast - the idea is to read the voltages from different batteries that are attached. I have a STM32L071 microcontroller. The programming is a bit different compared to the STM32F0 model. I am using platformio.
I found already very helpful information here:
Individually read distinct inputs with STM32F0 ADC
https://controllerstech.com/stm32-adc-multiple-channels/
https://deepbluembedded.com/stm32-adc-tutorial-complete-guide-with-examples/
However, unfortunately I cannot read out multiple channels. The problems are probably related to HAL_ADC_Init and HAL_ADC_ConfigChannel.
Here is a minimal code example:
#include <Arduino.h>
#include <STM32IntRef.h>
uint32_t a1=0, a2=0;
#define HAL_ADC_MODULE_ENABLED
ADC_HandleTypeDef hadc1;
void displaying(){
Serial.println("values:");
Serial.println("-------");
Serial.print("ch1 - ");
Serial.println(a1);
Serial.print("ch2 - ");
Serial.println(a2);
Serial.println("");
}
void config_ext_channel_ADC(uint32_t channel, bool val) {
hadc1.Instance = ADC1;
hadc1.Init.SamplingTime = ADC_SAMPLETIME_79CYCLES_5;
HAL_ADC_Init(&hadc1);
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = channel;
if (val == true) {
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
} else {
sConfig.Rank = ADC_RANK_NONE;
}
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
Serial.println("Error ADC Config Channel");
//Error_Handler();
}
}
uint32_t r_single_ext_channel_ADC(uint32_t channel) {
/* read the ADC and output result */
uint32_t digital_result;
config_ext_channel_ADC(channel, true);
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
digital_result = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
config_ext_channel_ADC(channel, false);
return digital_result;
}
void readBat() {
/* read voltages */
a1 = r_single_ext_channel_ADC(1);
a2 = r_single_ext_channel_ADC(PA2);
}
void setup() {
// put your setup code here, to run once:
// Serial monitor
Serial.begin(9600);
Serial.println(F("Starting now"));
// initialize pins for ADC
analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);
}
void loop() {
// put your main code here, to run repeatedly:
readBat();
displaying();
delay(2000);
}
The output is:
values:
-------
ch1 - 0
ch2 - 140
Sounds reasonable, but applying some voltages at the pins does not change the values.
Could somebody please provide me some advice, ideas?
Okay, in the meantime I found the problem. The software is fine; I took the Arduino framework and used analogRead().
I needed to clean all the solder flux from the PCB which caused some contacts between the pins.
Moreover, if one wants to use address the HAL directly, one should set the ClockDivider such that the ADC samples below 1 MHz.
Code to read different ADC channels (here ADC2 with 2 channels) separetly (Generated By CubeMX):
Note: We have to use ScanConvMode plus DiscontinuousConvMode and NO ContinuousConvMode.
/* ADC2 init function */
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 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ENABLE;
hadc2.Init.ContinuousConvMode = DISABLE;
hadc2.Init.DiscontinuousConvMode = ENABLE;
hadc2.Init.NbrOfDiscConversion = 1;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 2;
hadc2.Init.DMAContinuousRequests = DISABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_8;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_9;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC2_Init 2 */
/* USER CODE END ADC2_Init 2 */
}
Now, to read:
void readChannel(){
//read the next channel
HAL_ADC_Start(&hadc2);
uint8_t ret = HAL_ADC_PollForConversion(&hadc2, 1000 /*timeout*/);
uint16_t value = HAL_ADC_GetValue(hadc);
printf("HAL_ADC_PollForConversion status: %d, VALLLL: %d\n", ret, value);
}
int main(){
while(1){
//Automatically read the first channel (channel 8):
readChannel();
HAL_Delay(100);
//Automatically read the second channel (channel 9):
readChannel();
HAL_Delay(100);
}
}
Did you miss to set the io to analog in mode? It should be something like this somewhere (usually in your hal msp file, adc_init func).
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
edit => you missed it for ch1
analogReadResolution(ADC_RESOLUTION);
pinMode(PA1, INPUT);
//pinMode(BATTERY_SENSE_PIN2, INPUT);
pinMode(PA2, INPUT_ANALOG);
It should be the same as PA2, input is "digital mode".
I am using STM32CUBEMX to generate codes. In the example (Examples\UART\UART_Printf) of STM32WB55, I did not find __HAL_RCC_USART1_CLK_ENABLE(). I am very confused why it is not necessary to enable USART1 clock, but we need to enable GPIOB clock?
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_ODD;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
}
Both calls are necessary.
__HAL_RCC_USART1_CLK_ENABLE is invoked from HAL_UART_MspInit (see stm32wbxx_hal_msp.c), which in turn is invoked from HAL_UART_Init
This is the way, how library and Cube samples are organized. Higher level code fills main descriptor (huart1 in your case) with pointer to the periphery instance, base initialization parameters and calls the Init function with this descriptor. The Init function performs register initialization, but first calls the MspInit function, that must be implemented in the application code. The MspInit function performs additional initialization like enabling clocks, GPIO configuration, etc. All what doesn't fit a library code
MspInit is also implemented as empty function with weak attribute in the library by default, which means any other implementation will override the default one.
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);
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.
I am new to MCU programming. I'd like to test UART loopback (mirror) using HAL. IAR project was generated by CubeMX for STM32L071RZT6. This code is in the main eternal loop:
HAL_UART_Transmit(&huart2, str1, 5, 1000);
HAL_UART_Receive(&huart2, str2, 5, 1000);
I get only the 1st element filled in str2 (null-terminated string). How can I fix it?
/* USART2 init function */
static void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
You can't send & receive at the same time. HAL_UART_Transmit is a blocking function, so when the function returns the data has been sent. When you call HAL_UART_Receive the data has been received. You should do something like that:
HAL_UART_Receive_IT(&huart2, str2, 5);
HAL_UART_Transmit(&huart2, str1, 5, 1000);
You can do it by interrupt or by DMA, but you should start receive before send.