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.
Related
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.
I'm using an STM32F476, and I have configured ADC1 to read from 9 different inputs.
My goal is achieve 200Hz, which should be very achievable considering the speed of the ADC on these MCUs.
The issue I am experiencing is that it seems the ADC readings are "interrupted" about every 1.5 seconds or so.
What I've done to configure this (code below) is configured the ADC to use DMA, and TIM3 at 200Hz. When the TIM3 interrupt occurs I call HAL_ADC_Start_DMA() and store this in memory for 5 seconds. Once the reading is completed, I write it to the serial port.
Code config for ADC, timer, looks like so:
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV128;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 9;
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;
/** 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;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 11;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 33332;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
Interrupt on timer:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// start the ADC->DMA conversion
get_adc_dma();
}
This function pulls the ADC (9 channels) and stores it into an array. When it's done, it send the data to the serial port (send_data())
void get_adc_dma(void){
if (collect) {
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_CHANNELS);
memcpy(adc_pool[counter], adc_buffer, sizeof(adc_buffer));
counter++;
if (counter >= 1000) {
collect = false;
send_data();
}
}
}
My output isn't great: (one channel shown)
Suggestions on why this happening and solving it would be welcomed.
I wrote a little program that reads I2C values with interrupts: The Problem is that sometimes it just doesn't work after uploading. I just have to run it so many times until it works (not changing anything in the code). It seems like its just coincidence if it works or not.
Here are the Details:
Sensor: HMC 5983 or MPU-6050 (same problem)
Board: STM32F103RB (Nucleo 64)
Code (without the generated Cubemx stuff):
int main(void) {
/*/////////////////////Setup/////////////////////////*/
buf[0] = 0x00;
buf[1] = 0x78;
buf[2] = 0x80;
buf[3] = 0x00;
HAL_I2C_Master_Transmit(&hi2c1, Kompass_ADDR, buf, 4, 100);
/*//////////////////////Start of IT Routine//////////////////*/
buf[0] = 0x03;
HAL_I2C_Master_Transmit_IT(&hi2c1, Kompass_ADDR, buf, 1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
/*/////////////////////printing the value////////////////////////*/
sprintf((char*) Serial_buffer, " X %i \r\n", DataX);
HAL_UART_Transmit(&huart2, (uint8_t*) Serial_buffer, strlen((char*) Serial_buffer), 100);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c) {
HAL_I2C_Master_Receive_IT(&hi2c1, Kompass_ADDR, buf, 6);
}
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) {
DataX = ((int16_t) buf[0]) << 8 | buf[1];
buf[0] = 0x03;
HAL_I2C_Master_Transmit_IT(&hi2c1, Kompass_ADDR, buf, 1);
}
////////////////////////////I2C Init Function////////////////////////
static void MX_I2C1_Init(void) {
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK) {
Error_Handler();
}
}
After some Error searching I found out, that the error occurs when there I2C port is busy during the reading.
Does somebody have Experience with this I2C Problem?
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();
}
}
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.