2024-10-11 01:35 AM - last edited on 2024-11-06 03:13 PM by Andrew Neil
Hello,
I am trying to communicate with an SDI-12 sensor through my custom STM32L4 pcb. The communication that I am trying to achieve is from a 3.3V microcontroller. Thus, I used the SN74LVC1G240DBVT buffer to convert my UART to SDI-12 data one wire, and also I had a MOSFET which converts my 3.3V of the pin to 5V (I have checked that the hardware wiring and voltages working as expected). For my UART protocol, I have this configurations:
static void MX_UART5_Init(void)
{
/* USER CODE BEGIN UART5_Init 0 */
/* USER CODE END UART5_Init 0 */
/* USER CODE BEGIN UART5_Init 1 */
/* USER CODE END UART5_Init 1 */
huart5.Instance = UART5;
huart5.Init.BaudRate = 1200;
huart5.Init.WordLength = UART_WORDLENGTH_8B; // Including parity
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_EVEN;
huart5.Init.Mode = UART_MODE_TX_RX;
huart5.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart5.Init.OverSampling = UART_OVERSAMPLING_16;
huart5.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart5.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart5) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN UART5_Init 2 */
/* USER CODE END UART5_Init 2 */
}
Based on this link which I have took the idea of the buffer when the OE bit is low then the 5V are enabled to the pin and every action on the UART TX line should be the same on the SDI12-DATA line which it is, and after 15ms maximum I should have the response, but unfortunately I don't have the response from the sensor. The sensor is proper wired with 12V. I am trying to implement the SDI12 send command function based on some references online with break and marking events for 12ms and 9ms respectively, however it doesn't get any response. I set an oscilloscope to check what are being out from SDI12 line and they seem ok, however the sensor doesn't response to any of the commands that I tried. For commands I tried to ping the sensor with '0!' and to query its address with '?!' but nothing is working. The function where I am trying to communicate with it is the following:
/**
* @function _SDI12_send_command
*
* @brief This function sends a specific command to the SDI-12 sensor.
* @note Steps to be done:
* - 12 ms break on TX line.
* - 8.3 ms marking
* cmd: Command to send.
* cmd_len: Length of the command to send.
* response_buffer: Buffer to hold the sensor's response.
* res_len: Length of the expected response.
* @retval HAL Status structures definition.
*/
static HAL_StatusTypeDef _SDI12_send_command(const char cmd[], const uint8_t cmd_len, char response_buffer[], uint8_t res_len)
{
HAL_StatusTypeDef res;
// Step 1: Configure GPIO for break
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
// Step 2: Select SDI-12
HAL_GPIO_WritePin(SDI12_SELECT_GPIO_Port, SDI12_SELECT_Pin, GPIO_PIN_RESET);
//HAL_Delay(1);
// Step 3: Send break (low for at least 12 ms)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_SET);
HAL_Delay(12);
// Step 4: Marking condition (high for at least 8.3 ms)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET);
HAL_Delay(12);
// Step 5: Reconfigure the GPIO pin for UART TX
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Alternate = GPIO_AF_UART;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_Delay(1); // Set it to normilize the osciloscope outpu.
// Step 6: Transmit the command
res = HAL_UART_Transmit(&huart5, (uint8_t*)&cmd, cmd_len, 1000);
if (res != HAL_OK) {
printf("Error in transmitting UART data\r\n");
return HAL_ERROR;
}
// Step 7: Deselect SDI-12
HAL_GPIO_WritePin(SDI12_SELECT_GPIO_Port, SDI12_SELECT_Pin, GPIO_PIN_SET);
// Step 8: Wait for the sensor's response
uint8_t count = 0;
res = _SDI12_ReceiveLine(response_buffer, res_len, &count); // Make sure this function is correctly implemented
printf("response_buffer[0]=%d\r\n", response_buffer[0]);
printf("response_buffer[1]=%d\r\n", response_buffer[1]);
printf("response_buffer[2]=%d\r\n", response_buffer[2]);
return res;
}
Can anyone help me? I know that I am missing something but I can't continue further I had tried everything. I sent data with 7databits (including parity) I used reverse bit order, I set MSB first instead of LSB but nothing until now.
Solved! Go to Solution.
2024-10-15 02:08 AM - edited 2024-10-15 02:09 AM
I have found the solution to my problem. SDI12 uses negative logic, so data must be transmitted in "reverse order" but also start and stop bit must be in reverse order. Thus, you don't have to reverse the bits that you are sending to the SDI12 sensor, you supply need to change the idle state of TX line, which through the buffer SN74LVC1G240DBVT goes to the SDI12 data line. So the UART configuration needs to be:
BaudRate = 1200
WordLenght = 7 data bits
Parity = Even
Mode = RX & TX
Hardware flow control = None
Idle state of TX line = Low, you can achieve that by doing the following:
huartx.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_TXINVERT_INIT;
huartx.AdvancedInit.TxPinLevelInvert = UART_ADVFEATURE_TXINV_ENABLE;
If you are using the above buffer in order to convert UART to SDI12 then you have to check this datasheet. Notice how it handle the OE pin in the output waveform.
2024-10-15 02:08 AM - edited 2024-10-15 02:09 AM
I have found the solution to my problem. SDI12 uses negative logic, so data must be transmitted in "reverse order" but also start and stop bit must be in reverse order. Thus, you don't have to reverse the bits that you are sending to the SDI12 sensor, you supply need to change the idle state of TX line, which through the buffer SN74LVC1G240DBVT goes to the SDI12 data line. So the UART configuration needs to be:
BaudRate = 1200
WordLenght = 7 data bits
Parity = Even
Mode = RX & TX
Hardware flow control = None
Idle state of TX line = Low, you can achieve that by doing the following:
huartx.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_TXINVERT_INIT;
huartx.AdvancedInit.TxPinLevelInvert = UART_ADVFEATURE_TXINV_ENABLE;
If you are using the above buffer in order to convert UART to SDI12 then you have to check this datasheet. Notice how it handle the OE pin in the output waveform.