0

I just began to understand the embedded world (after Arduino, RPi, etc) with the STM32F103 and FreeRTOS + Libopencm3. My first challenge is to interface a DS18B20, temperature sensor with my microprocessor. The 1-Wire bus is quite easy to understand but not native supported so I followed your advised and go for 1-wire over UART with DMA.

DS18B20 has DATA on USART2TX (+4k7 pullup + diode) and USART2RX, VCC to 5V and GND.

Initialization of 1-Wire :

static void ow_init(void)
{
    // One-Wire
    // Already done : rcc_periph_clock_enable(RCC_GPIOA);
    gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
    gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);
    usart_set_baudrate(USART2, 115200);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
    usart_enable(USART2);

    rcc_periph_clock_enable(RCC_DMA1);
}

1-Wire Reset :

uint8_t ow_reset(void)
{
    usart_disable_rx_dma(USART2);
    usart_disable_tx_dma(USART2);

    usart_set_baudrate(USART2, 9600);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);

    usart_send(USART2, 0xf0);
    while(usart_get_flag(USART2, USART_SR_TC));
    uint8_t ow_presence;
    ow_presence = usart_recv(USART2);

    usart_set_baudrate(USART2, 115200);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX_RX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);

    if(ow_presence != 0xf0)
    {
        return 1;
    }

    return 0;
}

Getting the scratchpad with :

void ow_convert_to_scratchpad(void)
{
    const uint8_t convert_T[] = {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,  // 0xCC
                                 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00}; // 0x44

    dma_channel_reset(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&USART2_DR);
    dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) convert_T);
    dma_set_number_of_data(DMA1, DMA_CHANNEL7, sizeof(convert_T));
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
    dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
    dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);

    dma_enable_channel(DMA1, DMA_CHANNEL7);
    usart_enable_tx_dma(USART2);
}

uint16_t ow_get_scratchpad(void)
{
    const uint8_t read_scratch[] = {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,  // 0xCC
                                    0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,  // 0xBE
                                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

    uint8_t buf[8];

    dma_channel_reset(DMA1, DMA_CHANNEL6);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t)&USART2_DR);
    dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) buf);
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
    dma_set_number_of_data(DMA1, DMA_CHANNEL6, sizeof(read_scratch));
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT);
    dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT);
    dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_LOW);

    dma_channel_reset(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&USART2_DR);
    dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) read_scratch);
    dma_set_number_of_data(DMA1, DMA_CHANNEL7, sizeof(read_scratch));
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
    dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
    dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);

    dma_enable_channel(DMA1, DMA_CHANNEL6);
    dma_enable_channel(DMA1, DMA_CHANNEL7);
    usart_enable_tx_dma(USART2);
    usart_enable_rx_dma(USART2);

    while(dma_get_interrupt_flag(DMA1, DMA_CHANNEL6, DMA_TCIF));

    uint16_t tt = 0;

    for(int i=0;i<32; i++)
    {
        uart1_printf("Bit : %d \n\r", buf[i]);
        if(buf[i] == 0xff)
        {
            tt = (tt >> 1) | 0x8000;
        }
        else
        {
            tt = tt >> 1;
        }
    }
    return tt;
}

static void demo_task(void *args)
{

    (void)args;

    for (;;) {
        uart1_printf("Hello\n\r");
        uint8_t p = ow_reset();
        uart1_printf("presence = %d\n\r", p);
        ow_convert_to_scratchpad();
        for(int i=0; i<5000000; i++)
        {
            __asm__("nop");
        }
        ow_reset();
        uint16_t t = ow_get_scratchpad();
        uart1_printf("t = %d \n\r", t);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

And finally the task that tries to reach the DS18B20

static void demo_task(void *args)
{

    (void)args;

    for (;;) {
        ow_reset();
        ow_convert_to_scratchpad();
        vTaskDelay(pdMS_TO_TICKS(500));
        ow_reset();
        uint16_t t = ow_get_scratchpad();
        uart1_printf("t = %d \n\r", t);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

I receive some bits as 0xCC, 0xBE, 0xFF but no more answer.

  • Could you please point out your question more clearly? You presented plenty of background detail information, which is good. But it would be helpful to readers if you could point out the critical features of the communication more clearly. Can you create a minimal example out of this? Or indicate for us the point up to which the solution works, and where problems begin? – HelpingHand Apr 13 '20 at 21:20
  • You have to start by narrowing down the problem. Is it in the UART or in the DMA? Do a simple program that populates an array from incoming UART data with polling instead of DMA. Does that work? If so the problem is with the DMA. If not, try to narrow it down to software or hardware. – Lundin Apr 14 '20 at 06:32
  • Ok, it is a good idea. I try the easiest one : disable DMA and just a basic config for USART2. PA2 and PA3 are shunted. `usart_send(USART2, 0xFF); while(usart_get_flag(USART2, USART_SR_TC)); uart1_printf("Bit : %d \n\r", usart_recv(USART2));` And the output is "Bit : 0" again and again. I think the first problem is already here. – NicolasColsoul Apr 14 '20 at 09:26
  • My USART2 Config : `rcc_periph_clock_enable(RCC_GPIOA); gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX); gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX); usart_set_baudrate(USART2, 115200); usart_set_databits(USART2, 8); usart_set_stopbits(USART2, USART_STOPBITS_1); usart_set_mode(USART2, USART_MODE_TX_RX); usart_set_parity(USART2, USART_PARITY_NONE); usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); usart_enable(USART2);` – NicolasColsoul Apr 14 '20 at 10:05

2 Answers2

0

Ok, so

rcc_periph_clock_enable(RCC_USART2);

was missing so USART2 can't do its job. I can send and receive data now.

The reset function works except this line (it wait indefinitely) :

while(usart_get_flag(USART2, USART_SR_TC));

I don't understand why this flag is not true when the transmission is complete... But I have 0x00 on RX line so I think the sensor is responding (I hope...)

My function ow_convert_to_scratchpad with DMA looks like being blocking. I don"t know why...

I just tried (for fun...) to replace the whole DMA by hardcoding the sent of 0xCC, 0x44, 0xCC, 0xBE and the read but no answer (0x00) from the sensors.

0

I am kind of late to the party, but... Have you tried something a bit less convoluted first? (Simpler to check I mean)

Like asking a single DS18B20 its address?

Reset bus and check presence.
Send search ROM cmd (write byte 0xF0)
loop 64 times reading address bits from LSB to MSB {
   read bit i
   read bit i complement
   check they are 1 and 0 or the other way around
   send bit i back to device so it sends you back the next bit
}

At the end you have the 8 byte of the device address. 1 byte family 0x28 48 bit address 1 byte CRC8 to check the whole thing is correct.