From 2b4caf2b8165a0614d67943fc44e82b6e3b2e151 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 22 Jul 2018 00:20:43 +0200 Subject: [PATCH] DS18B20: Works --- nucleo-test/Src/test.c | 134 +++++++++++++++++++++++++++++++---------- 1 file changed, 103 insertions(+), 31 deletions(-) diff --git a/nucleo-test/Src/test.c b/nucleo-test/Src/test.c index 717771d..f49107f 100644 --- a/nucleo-test/Src/test.c +++ b/nucleo-test/Src/test.c @@ -421,29 +421,34 @@ void run_test(void) #else -static volatile uint32_t dma_buffer; +// DS18B20 Temperature Sensor -static void ds18b20_reset(void) +static volatile uint32_t ds_dma_buffer; + +static void ds_reset(void) { - debug_puts("DS18B20: Reset\r\n"); + // debug_puts("DS18B20: Reset\r\n"); LL_TIM_DisableCounter(TIM3); LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE); - LL_TIM_CC_SetDMAReqTrigger(TIM3, LL_TIM_CCDMAREQUEST_CC); - dma_buffer = 0xdeadbeef; - LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) &dma_buffer); + // DMA for reading pin state + ds_dma_buffer = 0xdeadbeef; + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) &ds_dma_buffer); LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) &THERMO_GPIO_Port->IDR); LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 1); LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4); LL_TIM_OC_InitTypeDef oc; + // CC1 is used to drive the DMA (read line state at specified time) LL_TIM_OC_StructInit(&oc); oc.OCMode = LL_TIM_OCMODE_FROZEN; oc.CompareValue = 560; LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH1, &oc); LL_TIM_EnableDMAReq_CC1(TIM3); + LL_TIM_CC_SetDMAReqTrigger(TIM3, LL_TIM_CCDMAREQUEST_CC); + // CC2 is used to generate pulses (return line to idle state at specified time) LL_TIM_OC_StructInit(&oc); oc.OCMode = LL_TIM_OCMODE_FORCED_ACTIVE; oc.OCState = LL_TIM_OCSTATE_ENABLE; @@ -451,33 +456,95 @@ static void ds18b20_reset(void) oc.OCPolarity = LL_TIM_OCPOLARITY_LOW; LL_TIM_OC_Init(TIM3, LL_TIM_CHANNEL_CH2, &oc); + // Set timer period to the length of the whole transaction LL_TIM_SetAutoReload(TIM3, 999); - LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE); + // Pull line down and start timer + LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE); LL_TIM_EnableCounter(TIM3); + // Wait until the timer expires while (LL_TIM_IsEnabledCounter(TIM3)) ; // Counter is automatically disabled at the end of cycle + // Disable DMA LL_TIM_DisableDMAReq_CC1(TIM3); LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4); - debug_printf("DMA = %08x [%u] (%u remains)\r\n", dma_buffer, !!(dma_buffer & THERMO_Pin), LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_4)); + // debug_printf("Init DMA: %08x [%u] (%u remains)\r\n", ds_dma_buffer, !!(ds_dma_buffer & THERMO_Pin), LL_DMA_GetDataLength(DMA1, LL_DMA_CHANNEL_4)); +} + +static void ds_send_byte(byte b) +{ + // debug_printf("DS write: %02x\r\n", b); + LL_TIM_SetAutoReload(TIM3, 99); // Each write slot takes 100μs + for (uint m=1; m < 0x100; m <<= 1) + { + LL_TIM_OC_SetCompareCH2(TIM3, ((b & m) ? 1 : 89)); // 1: 1μs pulse, 0: 89μs pulse + LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE); + LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE); + LL_TIM_EnableCounter(TIM3); + while (LL_TIM_IsEnabledCounter(TIM3)) + ; + } } -static void ds18b20_send_byte(byte b) +static byte ds_recv_byte(void) { - LL_TIM_SetAutoReload(TIM3, 99); - for (uint m=0x80; m; m >>= 1) + LL_TIM_SetAutoReload(TIM3, 79); // Each read slot takes 80μs + LL_TIM_OC_SetCompareCH2(TIM3, 1); // Generate 1μs pulse to start read slot + LL_TIM_OC_SetCompareCH1(TIM3, 8); // Sample data 8μs after start of slot + LL_TIM_EnableDMAReq_CC1(TIM3); + + uint out = 0; + for (uint m=1; m < 0x100; m <<= 1) { - LL_TIM_OC_SetCompareCH2(TIM3, ((b & m) ? 1 : 89)); + ds_dma_buffer = 0xdeadbeef; + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, 1); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4); LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_FORCED_ACTIVE); LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_INACTIVE); LL_TIM_EnableCounter(TIM3); while (LL_TIM_IsEnabledCounter(TIM3)) ; + // FIXME: Using the Pin constant directly is fragile! + // debug_printf("XXX %08x\r\n", ds_dma_buffer); + if (ds_dma_buffer & THERMO_Pin) + out |= m; + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4); } + + LL_TIM_DisableDMAReq_CC1(TIM3); + // debug_printf("DS read: %02x\r\n", out); + return out; +} + +static byte ds_buf[10]; + +static int ds_recv_block(uint n) +{ + uint crc = 0; + for (uint i=0; i> 7); + crc = (crc << 1) & 0xff; + if (k) + crc ^= 0x31; + b >>= 1; + } + } + + if (crc) + { + debug_printf("WARNING: Invalid CRC %02x\r\n", crc); + return 0; + } + return 1; } void run_test(void) @@ -485,32 +552,37 @@ void run_test(void) uint cnt = 0; debug_puts("Init\r\n"); - NVIC_DisableIRQ(TIM3_IRQn); + NVIC_DisableIRQ(TIM3_IRQn); // One day, we will handle everything from interrupts... -#if 0 - LL_GPIO_InitTypeDef GPIO_InitStruct; - GPIO_InitStruct.Pin = THERMO_Pin; - GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT; - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; - LL_GPIO_Init(THERMO_GPIO_Port, &GPIO_InitStruct); - LL_GPIO_SetOutputPin(THERMO_GPIO_Port, THERMO_Pin); -#endif + // Identify device + ds_reset(); + ds_send_byte(0x33); + ds_recv_block(8); - ds18b20_reset(); + // FIXME: Configure precision for (;;) { LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); + // debug_printf("Tick tock: %d\r\n", cnt); + + // Start measurement + ds_reset(); + ds_send_byte(0xcc); + ds_send_byte(0x44); + while (ds_recv_byte() != 0xff) + LL_mDelay(10); + + // Read scratch pad + ds_reset(); + ds_send_byte(0xcc); + ds_send_byte(0xbe); + ds_recv_block(9); + int t = (int16_t)(ds_buf[0] | (ds_buf[1] << 8)); + t = t*1000/16; + debug_printf("Temp: %d.%03d degC\r\n", t/1000, t%1000); - debug_printf("Tick tock: %d\r\n", cnt); - // ds18b20_send_byte(0xcc); - ds18b20_reset(); - - LL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); - - LL_mDelay(100); + LL_mDelay(1000); cnt++; } } -- 2.39.2