cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L072: No response from ATMOS22 sensor via SDI-12 over half-duplex USART

Ikram_safia11
Associate II

0

Hello,
I'm trying to communicate with an ATMOS22 weather sensor using the SDI-12 protocol on an STM32L072 microcontroller. I'm using USART1 in half-duplex mode , configured for 1200 baud , 7E1 parity , and inverted logic , as required by the SDI-12 specification.

Despite double-checking both my wiring and code — including using a level shifter between the sensor and the STM32 board — I'm not receiving any response at all from the sensor. The dataReceived flag is never set, and the log consistently shows "SDI-12 Response: TIMEOUT" after each command.

Here's what I've done so far:

Properly implemented the break (15ms LOW) and mark (12ms HIGH) signals before each command. Used GPIO toggling to simulate break/mark timing before switching back to UART mode. Configured USART1 for half-duplex mode , with TX/RX inversion enabled . Used HAL_UARTEx_ReceiveToIdle_IT() with a callback function to handle incoming data. Tried various SDI-12 commands such as aI!, aM!, aD0!, aR0!, etc.

Can anyone help me understand why the STM32 isn't receiving any data from the ATMOS22? Could this be due to a timing issue, incorrect configuration, or misunderstanding of the SDI-12 protocol?

Any advice would be greatly appreciated!

Best regards,

void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 1200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_EVEN; 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; // Inversion logique nécessaire pour SDI-12 huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_TXINVERT_INIT | UART_ADVFEATURE_RXINVERT_INIT; huart1.AdvancedInit.TxPinLevelInvert = UART_ADVFEATURE_TXINV_ENABLE; huart1.AdvancedInit.RxPinLevelInvert = UART_ADVFEATURE_RXINV_ENABLE; if (HAL_HalfDuplex_Init(&huart1) != HAL_OK) { Error_Handler();}} static HAL_StatusTypeDef _SDI12_send_command(const char cmd[], const uint8_t cmd_len, char response_buffer[], uint8_t res_len) { HAL_StatusTypeDef res; GPIO_InitTypeDef GPIO_InitStruct = {0}; // Configurer PA9 comme sortie pour générer break/mark GPIO_InitStruct.Pin = GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Break : 15 ms LOW HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET); HAL_Delay(15); // Mark : 12 ms HIGH HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); HAL_Delay(12); // Reconfigurer PA9 comme AF pour USART1 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Alternate = GPIO_AF4_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); HAL_Delay(5); HAL_HalfDuplex_EnableTransmitter(&huart1); HAL_Delay(20); // Envoyer la commande SDI-12 res = HAL_UART_Transmit(&huart1, (uint8_t*)cmd, cmd_len, 2000); HAL_Delay(100); // Lire la réponse uint8_t count = 0; res = _SDI12_ReceiveLine(response_buffer, res_len, &count); return res; } static HAL_StatusTypeDef _SDI12_ReceiveLine(char response_buffer[], uint8_t max_len, uint8_t *received_count) { HAL_StatusTypeDef status = HAL_OK; dataReceived = 0; rxSize = 0; memset(RxData, 0, sizeof(RxData)); HAL_HalfDuplex_EnableReceiver(&huart1); HAL_Delay(50); status = HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, sizeof(RxData)-1); if (status != HAL_OK) return HAL_ERROR; uint32_t timeout = 5000; uint32_t startTime = HAL_GetTick(); while (HAL_GetTick() - startTime < timeout) { if (dataReceived) break; HAL_Delay(10); } if (dataReceived && rxSize > 0) { uint8_t copy_len = (rxSize < max_len-1) ? rxSize : max_len-1; memcpy(response_buffer, RxData, copy_len); response_buffer[copy_len] = '\0'; *received_count = copy_len; status = HAL_OK; } else { *received_count = 0; status = HAL_TIMEOUT; } dataReceived = 0; return status; } void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { if(huart->Instance == USART1 && Size > 0) { rxSize = Size; dataReceived = 1; if(Size < sizeof(RxData)) { RxData[Size] = '\0'; } } } HAL_StatusTypeDef SDI12_SendCommand(const char* command, char* response, uint8_t response_size) { return _SDI12_send_command(command, strlen(command), response, response_size); } HAL_StatusTypeDef SDI12_GetSensorInfo(char address, char* info_buffer, uint8_t buffer_size) { char command[10]; snprintf(command, sizeof(command), "%cI!\r\n", address); return SDI12_SendCommand(command, info_buffer, buffer_size); } HAL_StatusTypeDef SDI12_StartMeasurement(char address, char* response, uint8_t buffer_size) { char command[10]; snprintf(command, sizeof(command), "%cM!\r\n", address); return SDI12_SendCommand(command, response, buffer_size); } HAL_StatusTypeDef SDI12_GetData(char address, uint8_t data_index, char* data_buffer, uint8_t buffer_size) { char command[10]; snprintf(command, sizeof(command), "%cD%d!\r\n", address, data_index); return SDI12_SendCommand(command, data_buffer, buffer_size); } void TestAtmos22(void) { char response[100], wind_data[100], temp_data[100]; HAL_StatusTypeDef status; printf("=== TEST ATMOS22 ===\r\n"); // Identifier le capteur status = SDI12_GetSensorInfo('1', response, sizeof(response)); if (status != HAL_OK) { status = SDI12_GetSensorInfo('0', response, sizeof(response)); } // Démarrer une mesure status = SDI12_StartMeasurement('0', response, sizeof(response)); // Attendre et lire les données int wait_time = 3; if (strlen(response) >= 4) { char time_str[4] = {0}; strncpy(time_str, &response[1], 3); wait_time = atoi(time_str); } HAL_Delay(wait_time * 1000); // Récupérer les mesures SDI12_GetData('0', 0, wind_data, sizeof(wind_data)); SDI12_GetData('0', 1, temp_data, sizeof(temp_data)); // Parser et afficher float ws, wd, gw, temp; if (SDI12_ParseWindData(wind_data, &ws, &wd, &gw)) { printf("Vitesse du vent: %.2f m/s\r\n", ws); printf("Direction du vent: %.1f°\r\n", wd); } if (SDI12_ParseTemperatureData(temp_data, &temp)) { printf("Température: %.2f°C\r\n", temp); } }
View more
1 REPLY 1
Ozone
Principal II

First, there is a "code formatting" tool available in the post editor. It's use is highly recommended for readability

Ozone_0-1748257393118.png

> Can anyone help me understand why the STM32 isn't receiving any data from the ATMOS22? Could this be due to a timing issue, incorrect configuration, or misunderstanding of the SDI-12 protocol?

Have you tried a scope or logic analyzer ?
Check the Rx pins sees any signal at all, up to the MCU pin.
And vice versa, check the transmissions of your MCU is visible on the bus.

I have no experience with said SDI-12 protocol, but half-duplex / bidirectional means you need specific hardware to attach a node, not just level shifting logic.