X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=nucleo-test%2FSrc%2Ftest.c;h=ed2bae4b6e29c8fcf73a7beb2efac5b74c489d80;hb=228f98a7bea12a3cc18aab18f50951d3256bc5fe;hp=4216c10f0caa4af0bd7835ebb0d3738a1de28a3e;hpb=8343c92a7acf238133fbd16870643a5ff25a146f;p=home-hw.git diff --git a/nucleo-test/Src/test.c b/nucleo-test/Src/test.c index 4216c10..ed2bae4 100644 --- a/nucleo-test/Src/test.c +++ b/nucleo-test/Src/test.c @@ -253,7 +253,7 @@ void run_test(void) } } -#else +#elif 0 static const byte Gentium23x32[] = { 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0xE0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x3F, 0xFE, 0x01, 0xE0, 0x3F, 0x3E, 0x00, 0x00, 0x7F, 0x1F, 0x00, 0x00, 0x7C, 0x0F, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0x78, 0x1F, 0x00, 0x00, 0x78, 0x3F, 0x00, 0x00, 0x78, 0x7F, 0x00, 0x00, 0x3E, 0xFE, 0x07, 0xC0, 0x3F, 0xFE, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0x0F, 0xF8, 0xFF, 0xFF, 0x07, 0xE0, 0xFF, 0xFF, 0x03, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0x0F, 0x00, // Code for char 0 @@ -419,4 +419,174 @@ void run_test(void) } } +#else + +// DS18B20 Temperature Sensor + +static volatile uint32_t ds_dma_buffer; + +static void ds_reset(void) +{ + // debug_puts("DS18B20: Reset\r\n"); + LL_TIM_DisableCounter(TIM3); + LL_TIM_SetOnePulseMode(TIM3, LL_TIM_ONEPULSEMODE_SINGLE); + + // 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; + oc.CompareValue = 480; + 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); + + // 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("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 byte ds_recv_byte(void) +{ + 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) + { + 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) +{ + uint cnt = 0; + + debug_puts("Init\r\n"); + NVIC_DisableIRQ(TIM3_IRQn); // One day, we will handle everything from interrupts... + + // Identify device + ds_reset(); + ds_send_byte(0x33); + ds_recv_block(8); + + // FIXME: Configure precision + + for (;;) + { + LL_GPIO_SetOutputPin(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; + + LL_GPIO_ResetOutputPin(LD2_GPIO_Port, LD2_Pin); + debug_printf("Temp: %d.%03d degC\r\n", t/1000, t%1000); + + LL_mDelay(1000); + cnt++; + } +} + #endif