2025-05-26 3:43 AM - edited 2025-05-26 4:35 AM
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);
}
}
2025-05-26 4:08 AM
First, there is a "code formatting" tool available in the post editor. It's use is highly recommended for readability
> 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.