]> mj.ucw.cz Git - home-hw.git/commitdiff
ds-test -> test-ds
authorMartin Mares <mj@ucw.cz>
Thu, 18 Jul 2019 09:45:45 +0000 (11:45 +0200)
committerMartin Mares <mj@ucw.cz>
Thu, 18 Jul 2019 09:45:45 +0000 (11:45 +0200)
12 files changed:
ds-test/Makefile [deleted file]
ds-test/ds18b20.c [deleted file]
ds-test/ds18b20.h [deleted file]
ds-test/test.c [deleted file]
ds-test/util-debug.c [deleted file]
ds-test/util.h [deleted file]
test-ds/Makefile [new file with mode: 0644]
test-ds/ds18b20.c [new file with mode: 0644]
test-ds/ds18b20.h [new file with mode: 0644]
test-ds/test.c [new file with mode: 0644]
test-ds/util-debug.c [new file with mode: 0644]
test-ds/util.h [new file with mode: 0644]

diff --git a/ds-test/Makefile b/ds-test/Makefile
deleted file mode 100644 (file)
index 3e3438f..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-BINARY=test
-OBJS=test.o util-debug.o ds18b20.o
-
-OPENCM3_DIR=/home/mj/stm/libopencm3
-DEVICE=stm32f103x8
-
-all: $(BINARY).elf $(BINARY).bin
-
-flash: all
-       ../bin/st-flash write $(BINARY).bin 0x8000000
-
-reset: all
-       ../bin/st-flash reset
-
-ifneq ($(V),1)
-Q              := @
-NULL           := 2>/dev/null
-endif
-
-include $(OPENCM3_DIR)/mk/genlink-config.mk
-
-PREFIX         ?= arm-none-eabi
-
-CC             := $(PREFIX)-gcc
-CXX            := $(PREFIX)-g++
-LD             := $(PREFIX)-gcc
-AR             := $(PREFIX)-ar
-AS             := $(PREFIX)-as
-OBJCOPY                := $(PREFIX)-objcopy
-OBJDUMP                := $(PREFIX)-objdump
-GDB            := $(PREFIX)-gdb
-OPT            := -Os
-DEBUG          := -ggdb3
-CSTD           ?= -std=c99
-
-TGT_CFLAGS     += $(OPT) $(CSTD) $(DEBUG)
-TGT_CFLAGS     += $(ARCH_FLAGS)
-TGT_CFLAGS     += -Wall -Wextra -Wshadow -Wimplicit-function-declaration
-TGT_CFLAGS     += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
-TGT_CFLAGS     += -fno-common -ffunction-sections -fdata-sections
-
-TGT_CPPFLAGS   += -MD
-
-TGT_LDFLAGS    += --static -nostartfiles
-TGT_LDFLAGS    += -T$(LDSCRIPT)
-TGT_LDFLAGS    += $(ARCH_FLAGS) $(DEBUG)
-TGT_LDFLAGS    += -Wl,-Map=$(*).map -Wl,--cref
-TGT_LDFLAGS    += -Wl,--gc-sections
-ifeq ($(V),99)
-TGT_LDFLAGS    += -Wl,--print-gc-sections
-endif
-
-LDLIBS         += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
-
-include $(OPENCM3_DIR)/mk/genlink-rules.mk
-
-%.bin: %.elf
-       @printf "  OBJCOPY $(*).bin\n"
-       $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin
-
-%.elf: $(OBJS) $(LDSCRIPT)
-       @printf "  LD      $(*).elf\n"
-       $(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $*.elf
-
-%.o: %.c
-       @printf "  CC      $(*).c\n"
-       $(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $*.o -c $*.c
-
-.PHONY: clean
-clean:
-       @printf "  CLEAN\n"
-       $(Q)rm -f *.elf *.bin *.o *.d *.map $(LDSCRIPT)
-
-%.stlink-flash: %.bin
-       @printf "  FLASH  $<\n"
-       $(STFLASH) write $(*).bin 0x8000000
-
-.SECONDEXPANSION:
-.SECONDARY:
-
--include $(OBJS:.o=.d)
diff --git a/ds-test/ds18b20.c b/ds-test/ds18b20.c
deleted file mode 100644 (file)
index 53df2a6..0000000
+++ /dev/null
@@ -1,419 +0,0 @@
-// DS18B20 Temperature Sensors
-
-#include "util.h"
-#include "ds18b20.h"
-
-#include <libopencm3/cm3/cortex.h>
-#include <libopencm3/stm32/dma.h>
-#include <libopencm3/stm32/gpio.h>
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/timer.h>
-#include <string.h>
-
-static volatile u32 ds_dma_buffer;
-
-#define DS_TIMER TIM3
-#define DS_GPIO GPIOA
-#define DS_PIN GPIO7
-#define DS_DMA DMA1
-#define DS_DMA_CH 6
-
-#define DS_DEBUG
-#undef DS_DEBUG2
-
-#ifdef DS_DEBUG
-#define DEBUG debug_printf
-#else
-#define DEBUG(xxx, ...) do { } while (0)
-#endif
-
-#ifdef DS_DEBUG2
-#define DEBUG2 debug_printf
-#else
-#define DEBUG2(xxx, ...) do { } while (0)
-#endif
-
-// Current temperature
-int ds_current_temp = DS_TEMP_UNKNOWN;
-
-// Auxiliary functions which are missing from libopencm3
-static inline bool timer_is_counter_enabled(u32 timer)
-{
-       return TIM_CR1(timer) & TIM_CR1_CEN;
-}
-
-static inline void timer_enable_dma_cc1(u32 timer)
-{
-       TIM_DIER(timer) |= TIM_DIER_CC1DE;
-}
-
-static inline void timer_disable_dma_cc1(u32 timer)
-{
-       TIM_DIER(timer) &= ~TIM_DIER_CC1DE;
-}
-
-static bool ds_reset(void)
-{
-       DEBUG2("DS18B20: Reset\n");
-       timer_disable_counter(DS_TIMER);
-       timer_one_shot_mode(DS_TIMER);
-
-       // DMA for reading pin state
-       ds_dma_buffer = 0xdeadbeef;
-       dma_set_memory_address(DS_DMA, DS_DMA_CH, (u32) &ds_dma_buffer);
-       dma_set_peripheral_address(DS_DMA, DS_DMA_CH, (u32) &GPIO_IDR(DS_GPIO));
-       dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
-       dma_enable_channel(DS_DMA, DS_DMA_CH);
-
-       // CC1 is used to drive the DMA (read line state at specified time)
-       timer_disable_oc_output(DS_TIMER, TIM_OC1);
-       timer_set_oc_mode(DS_TIMER, TIM_OC1, TIM_OCM_FROZEN);
-       timer_set_oc_value(DS_TIMER, TIM_OC1, 560);
-       timer_set_dma_on_compare_event(DS_TIMER);
-       timer_enable_dma_cc1(DS_TIMER);
-
-       // CC2 is used to generate pulses (return line to idle state at specified time)
-       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
-       timer_enable_oc_output(DS_TIMER, TIM_OC2);
-       timer_set_oc_value(DS_TIMER, TIM_OC2, 480);
-       timer_set_oc_polarity_low(DS_TIMER, TIM_OC2);
-
-       // Set timer period to the length of the whole transaction (1 ms)
-       timer_set_period(DS_TIMER, 999);
-
-       // Pull line down and start timer
-       cm_disable_interrupts();
-       timer_enable_counter(DS_TIMER);
-       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
-       cm_enable_interrupts();
-
-       // Wait until the timer expires
-       while (timer_is_counter_enabled(DS_TIMER))
-               ;
-       // Counter is automatically disabled at the end of cycle
-
-       // Disable DMA
-       timer_disable_dma_cc1(DS_TIMER);
-       dma_disable_channel(DS_DMA, DS_DMA_CH);
-
-       DEBUG2("Init DMA: %08x [%u] (%u remains)\n",
-              ds_dma_buffer,
-              !!(ds_dma_buffer & GPIO7),
-              dma_get_number_of_data(DS_DMA, DS_DMA_CH));
-
-       // Did the device respond?
-       if (ds_dma_buffer & GPIO7) {
-               DEBUG("DS18B20: Initialization failed\n");
-               return 0;
-       } else
-               return 1;
-}
-
-static void ds_send_bit(bool bit)
-{
-       timer_set_period(DS_TIMER, 99);                         // Each write slot takes 100 μs
-       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
-       timer_set_oc_value(DS_TIMER, TIM_OC2, (bit ? 3 : 89));  // 1: 3μs pulse, 0: 89μs pulse
-       cm_disable_interrupts();
-       // XXX: On STM32F1, we must configure the OC channel _after_ we enable the counter,
-       // otherwise OC triggers immediately. Reasons?
-       timer_enable_counter(DS_TIMER);
-       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
-       cm_enable_interrupts();
-       while (timer_is_counter_enabled(DS_TIMER))
-               ;
-}
-
-static void ds_send_byte(byte b)
-{
-       DEBUG2("DS write: %02x\n", b);
-       for (uint m = 1; m < 0x100; m <<= 1)
-               ds_send_bit(b & m);
-}
-
-static bool ds_recv_bit(void)
-{
-       timer_set_period(DS_TIMER, 79);                 // Each read slot takes 80μs
-       timer_set_oc_value(DS_TIMER, TIM_OC2, 2);       // Generate 2μs pulse to start read slot
-       timer_set_oc_value(DS_TIMER, TIM_OC1, 8);       // Sample data 8μs after start of slot
-       timer_enable_dma_cc1(DS_TIMER);
-
-       ds_dma_buffer = 0xdeadbeef;
-       dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
-       dma_enable_channel(DS_DMA, DS_DMA_CH);
-       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
-       cm_disable_interrupts();
-       timer_enable_counter(DS_TIMER);
-       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
-       cm_enable_interrupts();
-       while (timer_is_counter_enabled(DS_TIMER))
-               ;
-       // DEBUG2("XXX %08x\n", ds_dma_buffer);
-       bool out = ds_dma_buffer & GPIO7;
-       dma_disable_channel(DS_DMA, DS_DMA_CH);
-
-       timer_disable_dma_cc1(DS_TIMER);
-
-       return out;
-}
-
-static byte ds_recv_byte(void)
-{
-       uint out = 0;
-       for (uint m = 1; m < 0x100; m <<= 1) {
-               if (ds_recv_bit())
-                       out |= m;
-       }
-
-       DEBUG2("DS read: %02x\n", out);
-       return out;
-}
-
-static byte ds_buf[10];
-
-static byte ds_crc_block(uint n)
-{
-       /// XXX: This might be worth optimizing
-       uint crc = 0;
-
-       for (uint i = 0; i < n; i++) {
-               byte b = ds_buf[i];
-               for (uint j = 0; j < 8; j++) {
-                       uint k = (b & 1) ^ (crc >> 7);
-                       crc = (crc << 1) & 0xff;
-                       if (k)
-                               crc ^= 0x31;
-                       b >>= 1;
-               }
-       }
-
-       return crc;
-}
-
-static bool ds_recv_block(uint n)
-{
-       for (uint i = 0; i < n; i++)
-               ds_buf[i] = ds_recv_byte();
-
-       byte crc = ds_crc_block(n);
-       if (crc) {
-               DEBUG("DS18B20: Invalid CRC %02x\n", crc);
-               return 0;
-       }
-       return 1;
-}
-
-struct ds_sensor ds_sensors[DS_NUM_SENSORS];
-
-#if DS_NUM_SENSORS == 1
-
-static void ds_enumerate(void)
-{
-       if (!ds_reset())
-               return;
-
-       ds_send_byte(0x33);     // READ_ROM
-       if (!ds_recv_block(8))
-               return;
-
-       DEBUG("DS18B20: Found sensor ");
-       for (uint i = 0; i < 8; i++) {
-               DEBUG("%02x", ds_buf[i]);
-               ds_sensors[0].address[i] = ds_buf[i];
-       }
-       DEBUG("\n");
-}
-
-#else
-
-static void ds_enumerate(void)
-{
-       /*
-        *  The enumeration algorithm roughly follows the one described in the
-        *  Book of iButton Standards (Maxim Integrated Application Note 937).
-        *
-        *  It simulates depth-first search on the trie of all device IDs.
-        *  In each pass, it walks the trie from the root and recognizes branching nodes.
-        *
-        *  The old_choice variable remembers the deepest left branch taken in the
-        *  previous pass, new_choice is the same for the current pass.
-        */
-
-       DEBUG("DS18B20: Enumerate\n");
-
-       uint num_sensors = 0;
-       byte *addr = ds_buf;
-       byte old_choice = 0;
-
-       for (;;) {
-               if (!ds_reset()) {
-                       DEBUG("DS18B20: Enumeration found no sensor\n");
-                       return;
-               }
-
-               ds_send_byte(0xf0);     // SEARCH_ROM
-               byte new_choice = 0;
-               for (byte i=0; i<64; i++) {
-                       bool have_one = ds_recv_bit();
-                       bool have_zero = ds_recv_bit();
-                       bool old_bit = addr[i/8] & (1U << (i%8));
-                       bool new_bit;
-                       switch (2*have_one + have_zero) {
-                               case 3:
-                                       // This should not happen
-                                       DEBUG("DS18B20: Enumeration failed\n");
-                                       return;
-                               case 1:
-                                       // Only 0
-                                       new_bit = 0;
-                                       break;
-                               case 2:
-                                       // Only 1
-                                       new_bit = 1;
-                                       break;
-                               default:
-                                       // Both
-                                       if (i == old_choice)
-                                               new_bit = 1;
-                                       else if (i > old_choice) {
-                                               new_bit = 0;
-                                               new_choice = i;
-                                       } else {
-                                               new_bit = old_bit;
-                                               if (!new_bit)
-                                                       new_choice = i;
-                                       }
-                       }
-                       if (new_bit)
-                               addr[i/8] |= 1U << (i%8);
-                       else
-                               addr[i/8] &= ~(1U << (i%8));
-                       ds_send_bit(new_bit);
-               }
-
-               if (num_sensors >= DS_NUM_SENSORS) {
-                       DEBUG("DS18B20: Too many sensors\n");
-                       return;
-               }
-
-               DEBUG("DS18B20: Found sensor #%u: ", num_sensors);
-               for (byte i=0; i<8; i++)
-                       DEBUG("%02x", addr[i]);
-               if (ds_crc_block(8)) {
-                       DEBUG(" - invalid CRC!\n");
-               } else if (ds_buf[0] == 0x28) {
-                       DEBUG("\n");
-                       memcpy(ds_sensors[num_sensors].address, ds_buf, 8);
-                       num_sensors++;
-               } else {
-                       DEBUG(" - wrong type\n");
-               }
-
-               old_choice = new_choice;
-               if (!old_choice)
-                       break;
-       }
-}
-
-#endif
-
-void ds_init(void)
-{
-       DEBUG("DS18B20: Init\n");
-
-       for (uint i = 0; i < DS_NUM_SENSORS; i++) {
-               memset(ds_sensors[i].address, 0, 8);
-               ds_sensors[i].current_temp = DS_TEMP_UNKNOWN;
-       }
-
-       dma_set_read_from_peripheral(DS_DMA, DS_DMA_CH);
-       dma_set_priority(DS_DMA, DS_DMA_CH, DMA_CCR_PL_VERY_HIGH);
-       dma_disable_peripheral_increment_mode(DS_DMA, DS_DMA_CH);
-       dma_enable_memory_increment_mode(DS_DMA, DS_DMA_CH);
-       dma_set_peripheral_size(DS_DMA, DS_DMA_CH, DMA_CCR_PSIZE_16BIT);
-       dma_set_memory_size(DS_DMA, DS_DMA_CH, DMA_CCR_MSIZE_16BIT);
-
-       timer_set_prescaler(DS_TIMER, 71);              // 1 tick = 1 μs
-       timer_set_mode(DS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
-       timer_disable_preload(DS_TIMER);
-
-       gpio_set_mode(DS_GPIO, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO7);
-
-       ds_enumerate();
-
-       // FIXME: Configure precision?
-}
-
-#if DS_NUM_SENSORS == 1
-#define ds_current_id 0
-#else
-       static byte ds_current_id;
-#endif
-
-static bool ds_activate(void)
-{
-       if (!ds_reset()) {
-               DEBUG("DS18B20: Reset failed\n");
-               return false;
-       }
-#if DS_NUM_SENSORS == 1
-       ds_send_byte(0xcc);     // SKIP_ROM
-#else
-       ds_send_byte(0x55);     // MATCH_ROM
-       for (uint i = 0; i < 8; i++)
-               ds_send_byte(ds_sensors[ds_current_id].address[i]);
-#endif
-       return true;
-}
-
-void ds_step(void)
-{
-       static byte ds_running;
-       static byte ds_timeout;
-
-       if (!ds_running) {
-               // Start measurement
-#if DS_NUM_SENSORS != 1
-               uint maxn = DS_NUM_SENSORS;
-               do {
-                       if (!maxn--)
-                               return;
-                       ds_current_id++;
-                       if (ds_current_id >= DS_NUM_SENSORS)
-                               ds_current_id = 0;
-               } while (!ds_sensors[ds_current_id].address[0]);
-#endif
-               if (!ds_activate()) {
-                       ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
-                       return;
-               }
-               ds_send_byte(0x44);     // CONVERT_T
-               ds_running = 1;
-               ds_timeout = 255;
-       } else {
-               // Still running?
-               if (!ds_recv_bit()) {
-                       if (!ds_timeout--) {
-                               DEBUG("DS18B20 #%u: Timeout\n", ds_current_id);
-                               ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
-                               ds_running = 0;
-                       }
-                       return;
-               }
-               ds_running = 0;
-
-               // Read scratch pad
-               if (!ds_activate())
-                       return;
-               ds_send_byte(0xbe);     // READ_SCRATCHPAD
-               if (!ds_recv_block(9)) {
-                       ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
-                       return;
-               }
-               int t = (int16_t) (ds_buf[0] | (ds_buf[1] << 8));
-               t = t * 1000 / 16;
-
-               DEBUG("DS18B20 #%u: %d.%03d degC\n", ds_current_id, t / 1000, t % 1000);
-               ds_sensors[ds_current_id].current_temp = t;
-       }
-}
diff --git a/ds-test/ds18b20.h b/ds-test/ds18b20.h
deleted file mode 100644 (file)
index 6ca5d75..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// DS18B20 Temperature Sensors
-
-#ifndef _DS18B20_H
-#define _DS18B20_H
-
-// Maximum number of supported sensors
-#define DS_NUM_SENSORS 8
-
-struct ds_sensor {
-       byte address[8];        // All zeroes if sensor does not exist.
-                               // Otherwise, address[0] is guaranteed to be non-zero.
-       int current_temp;       // Temperature in m°C or DS_TEMP_UNKNOWN
-};
-
-extern struct ds_sensor ds_sensors[DS_NUM_SENSORS];
-
-#define DS_TEMP_UNKNOWN 0x7fffffff
-
-void ds_init(void);
-void ds_step(void);
-
-#endif
diff --git a/ds-test/test.c b/ds-test/test.c
deleted file mode 100644 (file)
index 309fc75..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "util.h"
-#include "ds18b20.h"
-
-#include <libopencm3/cm3/nvic.h>
-#include <libopencm3/cm3/systick.h>
-#include <libopencm3/stm32/rcc.h>
-#include <libopencm3/stm32/gpio.h>
-#include <libopencm3/stm32/usart.h>
-
-static void clock_setup(void)
-{
-       rcc_clock_setup_in_hse_8mhz_out_72mhz();
-
-       rcc_periph_clock_enable(RCC_GPIOA);
-       rcc_periph_clock_enable(RCC_GPIOC);
-       rcc_periph_clock_enable(RCC_USART1);
-       rcc_periph_clock_enable(RCC_TIM3);
-       rcc_periph_clock_enable(RCC_DMA1);
-}
-
-static void gpio_setup(void)
-{
-       gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
-}
-
-static volatile u32 ms_ticks;
-
-void sys_tick_handler(void)
-{
-       ms_ticks++;
-}
-
-static void tick_setup(void)
-{
-       systick_set_frequency(1000, 72000000);
-       systick_counter_enable();
-       systick_interrupt_enable();
-}
-
-static void delay_ms(uint ms)
-{
-       u32 start_ticks = ms_ticks;
-       while (ms_ticks - start_ticks < ms)
-               ;
-}
-
-static void usart_setup(void)
-{
-       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
-
-       usart_set_baudrate(USART1, 115200);
-       usart_set_databits(USART1, 8);
-       usart_set_stopbits(USART1, USART_STOPBITS_1);
-       usart_set_mode(USART1, USART_MODE_TX);
-       usart_set_parity(USART1, USART_PARITY_NONE);
-       usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
-
-       usart_enable(USART1);
-}
-
-int main(void)
-{
-       clock_setup();
-       gpio_setup();
-       tick_setup();
-       usart_setup();
-
-       ds_init();
-       for (;;) {
-               gpio_toggle(GPIOC, GPIO13);
-               delay_ms(100);
-               ds_step();
-       }
-
-       return 0;
-}
diff --git a/ds-test/util-debug.c b/ds-test/util-debug.c
deleted file mode 100644 (file)
index a1698cf..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-#include "util.h"
-
-#include <libopencm3/stm32/usart.h>
-
-#include <stdarg.h>
-#include <string.h>
-
-#ifdef DEBUG_SEMIHOSTING
-
-void semi_put_char(char c)
-{
-       // This is tricky, we need to work around GCC bugs
-       volatile char cc = c;
-       asm volatile (
-               "mov r0, #0x03\n"   /* SYS_WRITEC */
-               "mov r1, %[msg]\n"
-               "bkpt #0xAB\n"
-               :
-               : [msg] "r" (&cc)
-               : "r0", "r1"
-       );
-}
-
-void semi_write_string(char *c)
-{
-       asm volatile (
-               "mov r0, #0x04\n"   /* SYS_WRITE0 */
-               "mov r1, %[msg]\n"
-               "bkpt #0xAB\n"
-               :
-               : [msg] "r" (c)
-               : "r0", "r1"
-       );
-}
-
-#endif
-
-void debug_putc(int c)
-{
-#ifdef DEBUG_SEMIHOSTING
-       static char debug_buf[128];
-       static int debug_i;
-       debug_buf[debug_i++] = c;
-       if (c == '\n' || debug_i >= sizeof(debug_buf) - 1) {
-               debug_buf[debug_i] = 0;
-               semi_write_string(debug_buf);
-               debug_i = 0;
-       }
-#endif
-#ifdef DEBUG_USART
-       if (c == '\n')
-               usart_send_blocking(USART1, '\r');
-       usart_send_blocking(USART1, c);
-#endif
-}
-
-void debug_puts(const char *s)
-{
-       while (*s)
-               debug_putc(*s++);
-}
-
-enum printf_flags {
-       PF_ZERO_PAD = 1,
-       PF_SIGNED = 2,
-       PF_NEGATIVE = 4,
-       PF_UPPERCASE = 8,
-       PF_LEFT = 16,
-};
-
-static void printf_string(const char *s, uint width, uint flags)
-{
-       uint len = strlen(s);
-       uint pad = (len < width) ? width - len : 0;
-       char pad_char = (flags & PF_ZERO_PAD) ? '0' : ' ';
-
-       if (flags & PF_LEFT)
-               debug_puts(s);
-       while (pad--)
-               debug_putc(pad_char);
-       if (!(flags & PF_LEFT))
-               debug_puts(s);
-}
-
-static void printf_number(uint i, uint width, uint flags, uint base)
-{
-       char buf[16];
-       char *w = buf + sizeof(buf);
-
-       if (flags & PF_SIGNED) {
-               if ((int) i < 0) {
-                       i = - (int) i;
-                       flags |= PF_NEGATIVE;
-               }
-       }
-
-       *--w = 0;
-       do {
-               uint digit = i % base;
-               if (digit < 10)
-                       *--w = '0' + digit;
-               else
-                       *--w = ((flags & PF_UPPERCASE) ? 'A' : 'a') + digit - 10;
-               i /= base;
-       }
-       while (i);
-
-       if (flags & PF_NEGATIVE)
-               *--w = '-';
-
-       printf_string(w, width, flags);
-}
-
-void debug_printf(const char *fmt, ...)
-{
-       va_list args;
-       va_start(args, fmt);
-
-       while (*fmt) {
-               int c = *fmt++;
-               if (c != '%') {
-                       debug_putc(c);
-                       continue;
-               }
-
-               uint width = 0;
-               uint flags = 0;
-
-               if (*fmt == '-') {
-                       fmt++;
-                       flags |= PF_LEFT;
-               }
-
-               if (*fmt == '0') {
-                       fmt++;
-                       flags |= PF_ZERO_PAD;
-               }
-
-               while (*fmt >= '0' && *fmt <= '9')
-                       width = 10*width + *fmt++ - '0';
-
-               c = *fmt++;
-               switch (c) {
-                       case 'd':
-                               printf_number(va_arg(args, int), width, flags | PF_SIGNED, 10);
-                               break;
-                       case 'u':
-                               printf_number(va_arg(args, int), width, flags, 10);
-                               break;
-                       case 'X':
-                               flags |= PF_UPPERCASE;
-                               // fall-thru
-                       case 'x':
-                               printf_number(va_arg(args, int), width, flags, 16);
-                               break;
-                       case 's':
-                               printf_string(va_arg(args, char *), width, flags);
-                               break;
-                       default:
-                               debug_putc(c);
-                               continue;
-               }
-       }
-
-       va_end(args);
-}
diff --git a/ds-test/util.h b/ds-test/util.h
deleted file mode 100644 (file)
index 6d8c9cc..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#include <stdint.h>
-#include <stdbool.h>
-
-typedef unsigned int uint;
-typedef uint8_t byte;
-typedef uint16_t u16;
-typedef int16_t s16;
-typedef uint32_t u32;
-typedef int32_t s32;
-
-#define MIN(x,y) ((x) < (y) ? (x) : (y))
-#define MAX(x,y) ((x) > (y) ? (x) : (y))
-
-static inline uint get_u16_le(byte *p)
-{
-       return (p[1] << 8) | p[0];
-}
-
-static inline uint get_u16_be(byte *p)
-{
-       return (p[0] << 8) | p[1];
-}
-
-static inline uint get_u32_le(byte *p)
-{
-       return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
-}
-
-static inline uint get_u32_be(byte *p)
-{
-       return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
-}
-
-static inline void put_u16_le(byte *p, u16 x)
-{
-       p[0] = x;
-       p[1] = x >> 8;
-}
-
-static inline void put_u16_be(byte *p, u16 x)
-{
-       p[0] = x >> 8;
-       p[1] = x;
-}
-
-static inline void put_u32_be(byte *p, u32 x)
-{
-       p[0] = x >> 24;
-       p[1] = (x >> 16) & 0xff;
-       p[2] = (x >> 8) & 0xff;
-       p[3] = x & 0xff;
-}
-
-static inline void put_u32_le(byte *p, u32 x)
-{
-       p[3] = x >> 24;
-       p[2] = (x >> 16) & 0xff;
-       p[1] = (x >> 8) & 0xff;
-       p[0] = x & 0xff;
-}
-
-// debug.c
-
-// #define DEBUG_SEMIHOSTING
-#define DEBUG_USART USART1
-
-void debug_printf(const char *fmt, ...);
-void debug_puts(const char *s);
-void debug_putc(int c);
diff --git a/test-ds/Makefile b/test-ds/Makefile
new file mode 100644 (file)
index 0000000..3e3438f
--- /dev/null
@@ -0,0 +1,81 @@
+BINARY=test
+OBJS=test.o util-debug.o ds18b20.o
+
+OPENCM3_DIR=/home/mj/stm/libopencm3
+DEVICE=stm32f103x8
+
+all: $(BINARY).elf $(BINARY).bin
+
+flash: all
+       ../bin/st-flash write $(BINARY).bin 0x8000000
+
+reset: all
+       ../bin/st-flash reset
+
+ifneq ($(V),1)
+Q              := @
+NULL           := 2>/dev/null
+endif
+
+include $(OPENCM3_DIR)/mk/genlink-config.mk
+
+PREFIX         ?= arm-none-eabi
+
+CC             := $(PREFIX)-gcc
+CXX            := $(PREFIX)-g++
+LD             := $(PREFIX)-gcc
+AR             := $(PREFIX)-ar
+AS             := $(PREFIX)-as
+OBJCOPY                := $(PREFIX)-objcopy
+OBJDUMP                := $(PREFIX)-objdump
+GDB            := $(PREFIX)-gdb
+OPT            := -Os
+DEBUG          := -ggdb3
+CSTD           ?= -std=c99
+
+TGT_CFLAGS     += $(OPT) $(CSTD) $(DEBUG)
+TGT_CFLAGS     += $(ARCH_FLAGS)
+TGT_CFLAGS     += -Wall -Wextra -Wshadow -Wimplicit-function-declaration
+TGT_CFLAGS     += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
+TGT_CFLAGS     += -fno-common -ffunction-sections -fdata-sections
+
+TGT_CPPFLAGS   += -MD
+
+TGT_LDFLAGS    += --static -nostartfiles
+TGT_LDFLAGS    += -T$(LDSCRIPT)
+TGT_LDFLAGS    += $(ARCH_FLAGS) $(DEBUG)
+TGT_LDFLAGS    += -Wl,-Map=$(*).map -Wl,--cref
+TGT_LDFLAGS    += -Wl,--gc-sections
+ifeq ($(V),99)
+TGT_LDFLAGS    += -Wl,--print-gc-sections
+endif
+
+LDLIBS         += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
+
+include $(OPENCM3_DIR)/mk/genlink-rules.mk
+
+%.bin: %.elf
+       @printf "  OBJCOPY $(*).bin\n"
+       $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin
+
+%.elf: $(OBJS) $(LDSCRIPT)
+       @printf "  LD      $(*).elf\n"
+       $(Q)$(LD) $(TGT_LDFLAGS) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $*.elf
+
+%.o: %.c
+       @printf "  CC      $(*).c\n"
+       $(Q)$(CC) $(TGT_CFLAGS) $(CFLAGS) $(TGT_CPPFLAGS) $(CPPFLAGS) -o $*.o -c $*.c
+
+.PHONY: clean
+clean:
+       @printf "  CLEAN\n"
+       $(Q)rm -f *.elf *.bin *.o *.d *.map $(LDSCRIPT)
+
+%.stlink-flash: %.bin
+       @printf "  FLASH  $<\n"
+       $(STFLASH) write $(*).bin 0x8000000
+
+.SECONDEXPANSION:
+.SECONDARY:
+
+-include $(OBJS:.o=.d)
diff --git a/test-ds/ds18b20.c b/test-ds/ds18b20.c
new file mode 100644 (file)
index 0000000..53df2a6
--- /dev/null
@@ -0,0 +1,419 @@
+// DS18B20 Temperature Sensors
+
+#include "util.h"
+#include "ds18b20.h"
+
+#include <libopencm3/cm3/cortex.h>
+#include <libopencm3/stm32/dma.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/timer.h>
+#include <string.h>
+
+static volatile u32 ds_dma_buffer;
+
+#define DS_TIMER TIM3
+#define DS_GPIO GPIOA
+#define DS_PIN GPIO7
+#define DS_DMA DMA1
+#define DS_DMA_CH 6
+
+#define DS_DEBUG
+#undef DS_DEBUG2
+
+#ifdef DS_DEBUG
+#define DEBUG debug_printf
+#else
+#define DEBUG(xxx, ...) do { } while (0)
+#endif
+
+#ifdef DS_DEBUG2
+#define DEBUG2 debug_printf
+#else
+#define DEBUG2(xxx, ...) do { } while (0)
+#endif
+
+// Current temperature
+int ds_current_temp = DS_TEMP_UNKNOWN;
+
+// Auxiliary functions which are missing from libopencm3
+static inline bool timer_is_counter_enabled(u32 timer)
+{
+       return TIM_CR1(timer) & TIM_CR1_CEN;
+}
+
+static inline void timer_enable_dma_cc1(u32 timer)
+{
+       TIM_DIER(timer) |= TIM_DIER_CC1DE;
+}
+
+static inline void timer_disable_dma_cc1(u32 timer)
+{
+       TIM_DIER(timer) &= ~TIM_DIER_CC1DE;
+}
+
+static bool ds_reset(void)
+{
+       DEBUG2("DS18B20: Reset\n");
+       timer_disable_counter(DS_TIMER);
+       timer_one_shot_mode(DS_TIMER);
+
+       // DMA for reading pin state
+       ds_dma_buffer = 0xdeadbeef;
+       dma_set_memory_address(DS_DMA, DS_DMA_CH, (u32) &ds_dma_buffer);
+       dma_set_peripheral_address(DS_DMA, DS_DMA_CH, (u32) &GPIO_IDR(DS_GPIO));
+       dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
+       dma_enable_channel(DS_DMA, DS_DMA_CH);
+
+       // CC1 is used to drive the DMA (read line state at specified time)
+       timer_disable_oc_output(DS_TIMER, TIM_OC1);
+       timer_set_oc_mode(DS_TIMER, TIM_OC1, TIM_OCM_FROZEN);
+       timer_set_oc_value(DS_TIMER, TIM_OC1, 560);
+       timer_set_dma_on_compare_event(DS_TIMER);
+       timer_enable_dma_cc1(DS_TIMER);
+
+       // CC2 is used to generate pulses (return line to idle state at specified time)
+       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
+       timer_enable_oc_output(DS_TIMER, TIM_OC2);
+       timer_set_oc_value(DS_TIMER, TIM_OC2, 480);
+       timer_set_oc_polarity_low(DS_TIMER, TIM_OC2);
+
+       // Set timer period to the length of the whole transaction (1 ms)
+       timer_set_period(DS_TIMER, 999);
+
+       // Pull line down and start timer
+       cm_disable_interrupts();
+       timer_enable_counter(DS_TIMER);
+       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
+       cm_enable_interrupts();
+
+       // Wait until the timer expires
+       while (timer_is_counter_enabled(DS_TIMER))
+               ;
+       // Counter is automatically disabled at the end of cycle
+
+       // Disable DMA
+       timer_disable_dma_cc1(DS_TIMER);
+       dma_disable_channel(DS_DMA, DS_DMA_CH);
+
+       DEBUG2("Init DMA: %08x [%u] (%u remains)\n",
+              ds_dma_buffer,
+              !!(ds_dma_buffer & GPIO7),
+              dma_get_number_of_data(DS_DMA, DS_DMA_CH));
+
+       // Did the device respond?
+       if (ds_dma_buffer & GPIO7) {
+               DEBUG("DS18B20: Initialization failed\n");
+               return 0;
+       } else
+               return 1;
+}
+
+static void ds_send_bit(bool bit)
+{
+       timer_set_period(DS_TIMER, 99);                         // Each write slot takes 100 μs
+       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
+       timer_set_oc_value(DS_TIMER, TIM_OC2, (bit ? 3 : 89));  // 1: 3μs pulse, 0: 89μs pulse
+       cm_disable_interrupts();
+       // XXX: On STM32F1, we must configure the OC channel _after_ we enable the counter,
+       // otherwise OC triggers immediately. Reasons?
+       timer_enable_counter(DS_TIMER);
+       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
+       cm_enable_interrupts();
+       while (timer_is_counter_enabled(DS_TIMER))
+               ;
+}
+
+static void ds_send_byte(byte b)
+{
+       DEBUG2("DS write: %02x\n", b);
+       for (uint m = 1; m < 0x100; m <<= 1)
+               ds_send_bit(b & m);
+}
+
+static bool ds_recv_bit(void)
+{
+       timer_set_period(DS_TIMER, 79);                 // Each read slot takes 80μs
+       timer_set_oc_value(DS_TIMER, TIM_OC2, 2);       // Generate 2μs pulse to start read slot
+       timer_set_oc_value(DS_TIMER, TIM_OC1, 8);       // Sample data 8μs after start of slot
+       timer_enable_dma_cc1(DS_TIMER);
+
+       ds_dma_buffer = 0xdeadbeef;
+       dma_set_number_of_data(DS_DMA, DS_DMA_CH, 1);
+       dma_enable_channel(DS_DMA, DS_DMA_CH);
+       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_FORCE_HIGH);
+       cm_disable_interrupts();
+       timer_enable_counter(DS_TIMER);
+       timer_set_oc_mode(DS_TIMER, TIM_OC2, TIM_OCM_INACTIVE);
+       cm_enable_interrupts();
+       while (timer_is_counter_enabled(DS_TIMER))
+               ;
+       // DEBUG2("XXX %08x\n", ds_dma_buffer);
+       bool out = ds_dma_buffer & GPIO7;
+       dma_disable_channel(DS_DMA, DS_DMA_CH);
+
+       timer_disable_dma_cc1(DS_TIMER);
+
+       return out;
+}
+
+static byte ds_recv_byte(void)
+{
+       uint out = 0;
+       for (uint m = 1; m < 0x100; m <<= 1) {
+               if (ds_recv_bit())
+                       out |= m;
+       }
+
+       DEBUG2("DS read: %02x\n", out);
+       return out;
+}
+
+static byte ds_buf[10];
+
+static byte ds_crc_block(uint n)
+{
+       /// XXX: This might be worth optimizing
+       uint crc = 0;
+
+       for (uint i = 0; i < n; i++) {
+               byte b = ds_buf[i];
+               for (uint j = 0; j < 8; j++) {
+                       uint k = (b & 1) ^ (crc >> 7);
+                       crc = (crc << 1) & 0xff;
+                       if (k)
+                               crc ^= 0x31;
+                       b >>= 1;
+               }
+       }
+
+       return crc;
+}
+
+static bool ds_recv_block(uint n)
+{
+       for (uint i = 0; i < n; i++)
+               ds_buf[i] = ds_recv_byte();
+
+       byte crc = ds_crc_block(n);
+       if (crc) {
+               DEBUG("DS18B20: Invalid CRC %02x\n", crc);
+               return 0;
+       }
+       return 1;
+}
+
+struct ds_sensor ds_sensors[DS_NUM_SENSORS];
+
+#if DS_NUM_SENSORS == 1
+
+static void ds_enumerate(void)
+{
+       if (!ds_reset())
+               return;
+
+       ds_send_byte(0x33);     // READ_ROM
+       if (!ds_recv_block(8))
+               return;
+
+       DEBUG("DS18B20: Found sensor ");
+       for (uint i = 0; i < 8; i++) {
+               DEBUG("%02x", ds_buf[i]);
+               ds_sensors[0].address[i] = ds_buf[i];
+       }
+       DEBUG("\n");
+}
+
+#else
+
+static void ds_enumerate(void)
+{
+       /*
+        *  The enumeration algorithm roughly follows the one described in the
+        *  Book of iButton Standards (Maxim Integrated Application Note 937).
+        *
+        *  It simulates depth-first search on the trie of all device IDs.
+        *  In each pass, it walks the trie from the root and recognizes branching nodes.
+        *
+        *  The old_choice variable remembers the deepest left branch taken in the
+        *  previous pass, new_choice is the same for the current pass.
+        */
+
+       DEBUG("DS18B20: Enumerate\n");
+
+       uint num_sensors = 0;
+       byte *addr = ds_buf;
+       byte old_choice = 0;
+
+       for (;;) {
+               if (!ds_reset()) {
+                       DEBUG("DS18B20: Enumeration found no sensor\n");
+                       return;
+               }
+
+               ds_send_byte(0xf0);     // SEARCH_ROM
+               byte new_choice = 0;
+               for (byte i=0; i<64; i++) {
+                       bool have_one = ds_recv_bit();
+                       bool have_zero = ds_recv_bit();
+                       bool old_bit = addr[i/8] & (1U << (i%8));
+                       bool new_bit;
+                       switch (2*have_one + have_zero) {
+                               case 3:
+                                       // This should not happen
+                                       DEBUG("DS18B20: Enumeration failed\n");
+                                       return;
+                               case 1:
+                                       // Only 0
+                                       new_bit = 0;
+                                       break;
+                               case 2:
+                                       // Only 1
+                                       new_bit = 1;
+                                       break;
+                               default:
+                                       // Both
+                                       if (i == old_choice)
+                                               new_bit = 1;
+                                       else if (i > old_choice) {
+                                               new_bit = 0;
+                                               new_choice = i;
+                                       } else {
+                                               new_bit = old_bit;
+                                               if (!new_bit)
+                                                       new_choice = i;
+                                       }
+                       }
+                       if (new_bit)
+                               addr[i/8] |= 1U << (i%8);
+                       else
+                               addr[i/8] &= ~(1U << (i%8));
+                       ds_send_bit(new_bit);
+               }
+
+               if (num_sensors >= DS_NUM_SENSORS) {
+                       DEBUG("DS18B20: Too many sensors\n");
+                       return;
+               }
+
+               DEBUG("DS18B20: Found sensor #%u: ", num_sensors);
+               for (byte i=0; i<8; i++)
+                       DEBUG("%02x", addr[i]);
+               if (ds_crc_block(8)) {
+                       DEBUG(" - invalid CRC!\n");
+               } else if (ds_buf[0] == 0x28) {
+                       DEBUG("\n");
+                       memcpy(ds_sensors[num_sensors].address, ds_buf, 8);
+                       num_sensors++;
+               } else {
+                       DEBUG(" - wrong type\n");
+               }
+
+               old_choice = new_choice;
+               if (!old_choice)
+                       break;
+       }
+}
+
+#endif
+
+void ds_init(void)
+{
+       DEBUG("DS18B20: Init\n");
+
+       for (uint i = 0; i < DS_NUM_SENSORS; i++) {
+               memset(ds_sensors[i].address, 0, 8);
+               ds_sensors[i].current_temp = DS_TEMP_UNKNOWN;
+       }
+
+       dma_set_read_from_peripheral(DS_DMA, DS_DMA_CH);
+       dma_set_priority(DS_DMA, DS_DMA_CH, DMA_CCR_PL_VERY_HIGH);
+       dma_disable_peripheral_increment_mode(DS_DMA, DS_DMA_CH);
+       dma_enable_memory_increment_mode(DS_DMA, DS_DMA_CH);
+       dma_set_peripheral_size(DS_DMA, DS_DMA_CH, DMA_CCR_PSIZE_16BIT);
+       dma_set_memory_size(DS_DMA, DS_DMA_CH, DMA_CCR_MSIZE_16BIT);
+
+       timer_set_prescaler(DS_TIMER, 71);              // 1 tick = 1 μs
+       timer_set_mode(DS_TIMER, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+       timer_disable_preload(DS_TIMER);
+
+       gpio_set_mode(DS_GPIO, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO7);
+
+       ds_enumerate();
+
+       // FIXME: Configure precision?
+}
+
+#if DS_NUM_SENSORS == 1
+#define ds_current_id 0
+#else
+       static byte ds_current_id;
+#endif
+
+static bool ds_activate(void)
+{
+       if (!ds_reset()) {
+               DEBUG("DS18B20: Reset failed\n");
+               return false;
+       }
+#if DS_NUM_SENSORS == 1
+       ds_send_byte(0xcc);     // SKIP_ROM
+#else
+       ds_send_byte(0x55);     // MATCH_ROM
+       for (uint i = 0; i < 8; i++)
+               ds_send_byte(ds_sensors[ds_current_id].address[i]);
+#endif
+       return true;
+}
+
+void ds_step(void)
+{
+       static byte ds_running;
+       static byte ds_timeout;
+
+       if (!ds_running) {
+               // Start measurement
+#if DS_NUM_SENSORS != 1
+               uint maxn = DS_NUM_SENSORS;
+               do {
+                       if (!maxn--)
+                               return;
+                       ds_current_id++;
+                       if (ds_current_id >= DS_NUM_SENSORS)
+                               ds_current_id = 0;
+               } while (!ds_sensors[ds_current_id].address[0]);
+#endif
+               if (!ds_activate()) {
+                       ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
+                       return;
+               }
+               ds_send_byte(0x44);     // CONVERT_T
+               ds_running = 1;
+               ds_timeout = 255;
+       } else {
+               // Still running?
+               if (!ds_recv_bit()) {
+                       if (!ds_timeout--) {
+                               DEBUG("DS18B20 #%u: Timeout\n", ds_current_id);
+                               ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
+                               ds_running = 0;
+                       }
+                       return;
+               }
+               ds_running = 0;
+
+               // Read scratch pad
+               if (!ds_activate())
+                       return;
+               ds_send_byte(0xbe);     // READ_SCRATCHPAD
+               if (!ds_recv_block(9)) {
+                       ds_sensors[ds_current_id].current_temp = DS_TEMP_UNKNOWN;
+                       return;
+               }
+               int t = (int16_t) (ds_buf[0] | (ds_buf[1] << 8));
+               t = t * 1000 / 16;
+
+               DEBUG("DS18B20 #%u: %d.%03d degC\n", ds_current_id, t / 1000, t % 1000);
+               ds_sensors[ds_current_id].current_temp = t;
+       }
+}
diff --git a/test-ds/ds18b20.h b/test-ds/ds18b20.h
new file mode 100644 (file)
index 0000000..6ca5d75
--- /dev/null
@@ -0,0 +1,22 @@
+// DS18B20 Temperature Sensors
+
+#ifndef _DS18B20_H
+#define _DS18B20_H
+
+// Maximum number of supported sensors
+#define DS_NUM_SENSORS 8
+
+struct ds_sensor {
+       byte address[8];        // All zeroes if sensor does not exist.
+                               // Otherwise, address[0] is guaranteed to be non-zero.
+       int current_temp;       // Temperature in m°C or DS_TEMP_UNKNOWN
+};
+
+extern struct ds_sensor ds_sensors[DS_NUM_SENSORS];
+
+#define DS_TEMP_UNKNOWN 0x7fffffff
+
+void ds_init(void);
+void ds_step(void);
+
+#endif
diff --git a/test-ds/test.c b/test-ds/test.c
new file mode 100644 (file)
index 0000000..309fc75
--- /dev/null
@@ -0,0 +1,76 @@
+#include "util.h"
+#include "ds18b20.h"
+
+#include <libopencm3/cm3/nvic.h>
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/usart.h>
+
+static void clock_setup(void)
+{
+       rcc_clock_setup_in_hse_8mhz_out_72mhz();
+
+       rcc_periph_clock_enable(RCC_GPIOA);
+       rcc_periph_clock_enable(RCC_GPIOC);
+       rcc_periph_clock_enable(RCC_USART1);
+       rcc_periph_clock_enable(RCC_TIM3);
+       rcc_periph_clock_enable(RCC_DMA1);
+}
+
+static void gpio_setup(void)
+{
+       gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+}
+
+static volatile u32 ms_ticks;
+
+void sys_tick_handler(void)
+{
+       ms_ticks++;
+}
+
+static void tick_setup(void)
+{
+       systick_set_frequency(1000, 72000000);
+       systick_counter_enable();
+       systick_interrupt_enable();
+}
+
+static void delay_ms(uint ms)
+{
+       u32 start_ticks = ms_ticks;
+       while (ms_ticks - start_ticks < ms)
+               ;
+}
+
+static void usart_setup(void)
+{
+       gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART1_TX);
+
+       usart_set_baudrate(USART1, 115200);
+       usart_set_databits(USART1, 8);
+       usart_set_stopbits(USART1, USART_STOPBITS_1);
+       usart_set_mode(USART1, USART_MODE_TX);
+       usart_set_parity(USART1, USART_PARITY_NONE);
+       usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
+
+       usart_enable(USART1);
+}
+
+int main(void)
+{
+       clock_setup();
+       gpio_setup();
+       tick_setup();
+       usart_setup();
+
+       ds_init();
+       for (;;) {
+               gpio_toggle(GPIOC, GPIO13);
+               delay_ms(100);
+               ds_step();
+       }
+
+       return 0;
+}
diff --git a/test-ds/util-debug.c b/test-ds/util-debug.c
new file mode 100644 (file)
index 0000000..a1698cf
--- /dev/null
@@ -0,0 +1,166 @@
+#include "util.h"
+
+#include <libopencm3/stm32/usart.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef DEBUG_SEMIHOSTING
+
+void semi_put_char(char c)
+{
+       // This is tricky, we need to work around GCC bugs
+       volatile char cc = c;
+       asm volatile (
+               "mov r0, #0x03\n"   /* SYS_WRITEC */
+               "mov r1, %[msg]\n"
+               "bkpt #0xAB\n"
+               :
+               : [msg] "r" (&cc)
+               : "r0", "r1"
+       );
+}
+
+void semi_write_string(char *c)
+{
+       asm volatile (
+               "mov r0, #0x04\n"   /* SYS_WRITE0 */
+               "mov r1, %[msg]\n"
+               "bkpt #0xAB\n"
+               :
+               : [msg] "r" (c)
+               : "r0", "r1"
+       );
+}
+
+#endif
+
+void debug_putc(int c)
+{
+#ifdef DEBUG_SEMIHOSTING
+       static char debug_buf[128];
+       static int debug_i;
+       debug_buf[debug_i++] = c;
+       if (c == '\n' || debug_i >= sizeof(debug_buf) - 1) {
+               debug_buf[debug_i] = 0;
+               semi_write_string(debug_buf);
+               debug_i = 0;
+       }
+#endif
+#ifdef DEBUG_USART
+       if (c == '\n')
+               usart_send_blocking(USART1, '\r');
+       usart_send_blocking(USART1, c);
+#endif
+}
+
+void debug_puts(const char *s)
+{
+       while (*s)
+               debug_putc(*s++);
+}
+
+enum printf_flags {
+       PF_ZERO_PAD = 1,
+       PF_SIGNED = 2,
+       PF_NEGATIVE = 4,
+       PF_UPPERCASE = 8,
+       PF_LEFT = 16,
+};
+
+static void printf_string(const char *s, uint width, uint flags)
+{
+       uint len = strlen(s);
+       uint pad = (len < width) ? width - len : 0;
+       char pad_char = (flags & PF_ZERO_PAD) ? '0' : ' ';
+
+       if (flags & PF_LEFT)
+               debug_puts(s);
+       while (pad--)
+               debug_putc(pad_char);
+       if (!(flags & PF_LEFT))
+               debug_puts(s);
+}
+
+static void printf_number(uint i, uint width, uint flags, uint base)
+{
+       char buf[16];
+       char *w = buf + sizeof(buf);
+
+       if (flags & PF_SIGNED) {
+               if ((int) i < 0) {
+                       i = - (int) i;
+                       flags |= PF_NEGATIVE;
+               }
+       }
+
+       *--w = 0;
+       do {
+               uint digit = i % base;
+               if (digit < 10)
+                       *--w = '0' + digit;
+               else
+                       *--w = ((flags & PF_UPPERCASE) ? 'A' : 'a') + digit - 10;
+               i /= base;
+       }
+       while (i);
+
+       if (flags & PF_NEGATIVE)
+               *--w = '-';
+
+       printf_string(w, width, flags);
+}
+
+void debug_printf(const char *fmt, ...)
+{
+       va_list args;
+       va_start(args, fmt);
+
+       while (*fmt) {
+               int c = *fmt++;
+               if (c != '%') {
+                       debug_putc(c);
+                       continue;
+               }
+
+               uint width = 0;
+               uint flags = 0;
+
+               if (*fmt == '-') {
+                       fmt++;
+                       flags |= PF_LEFT;
+               }
+
+               if (*fmt == '0') {
+                       fmt++;
+                       flags |= PF_ZERO_PAD;
+               }
+
+               while (*fmt >= '0' && *fmt <= '9')
+                       width = 10*width + *fmt++ - '0';
+
+               c = *fmt++;
+               switch (c) {
+                       case 'd':
+                               printf_number(va_arg(args, int), width, flags | PF_SIGNED, 10);
+                               break;
+                       case 'u':
+                               printf_number(va_arg(args, int), width, flags, 10);
+                               break;
+                       case 'X':
+                               flags |= PF_UPPERCASE;
+                               // fall-thru
+                       case 'x':
+                               printf_number(va_arg(args, int), width, flags, 16);
+                               break;
+                       case 's':
+                               printf_string(va_arg(args, char *), width, flags);
+                               break;
+                       default:
+                               debug_putc(c);
+                               continue;
+               }
+       }
+
+       va_end(args);
+}
diff --git a/test-ds/util.h b/test-ds/util.h
new file mode 100644 (file)
index 0000000..6d8c9cc
--- /dev/null
@@ -0,0 +1,69 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef unsigned int uint;
+typedef uint8_t byte;
+typedef uint16_t u16;
+typedef int16_t s16;
+typedef uint32_t u32;
+typedef int32_t s32;
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+static inline uint get_u16_le(byte *p)
+{
+       return (p[1] << 8) | p[0];
+}
+
+static inline uint get_u16_be(byte *p)
+{
+       return (p[0] << 8) | p[1];
+}
+
+static inline uint get_u32_le(byte *p)
+{
+       return (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
+}
+
+static inline uint get_u32_be(byte *p)
+{
+       return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+}
+
+static inline void put_u16_le(byte *p, u16 x)
+{
+       p[0] = x;
+       p[1] = x >> 8;
+}
+
+static inline void put_u16_be(byte *p, u16 x)
+{
+       p[0] = x >> 8;
+       p[1] = x;
+}
+
+static inline void put_u32_be(byte *p, u32 x)
+{
+       p[0] = x >> 24;
+       p[1] = (x >> 16) & 0xff;
+       p[2] = (x >> 8) & 0xff;
+       p[3] = x & 0xff;
+}
+
+static inline void put_u32_le(byte *p, u32 x)
+{
+       p[3] = x >> 24;
+       p[2] = (x >> 16) & 0xff;
+       p[1] = (x >> 8) & 0xff;
+       p[0] = x & 0xff;
+}
+
+// debug.c
+
+// #define DEBUG_SEMIHOSTING
+#define DEBUG_USART USART1
+
+void debug_printf(const char *fmt, ...);
+void debug_puts(const char *s);
+void debug_putc(int c);