From eca831982076a200b18389b058bfa382e20cd9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 29 Jan 2018 22:37:12 +0100 Subject: [PATCH] onewire basic impl + fixed a bug in usec delays --- platform/timebase.c | 17 ++- units/1wire/_ow_commands.h | 25 +++++ units/1wire/_ow_internal.h | 80 ++++++++++++++ units/1wire/_ow_ll.c | 193 ++++++++++++++++++++++++++++++++ units/1wire/unit_1wire.c | 219 ++----------------------------------- 5 files changed, 318 insertions(+), 216 deletions(-) create mode 100644 units/1wire/_ow_commands.h create mode 100644 units/1wire/_ow_internal.h create mode 100644 units/1wire/_ow_ll.c diff --git a/platform/timebase.c b/platform/timebase.c index d37e31d..932c92a 100644 --- a/platform/timebase.c +++ b/platform/timebase.c @@ -95,17 +95,24 @@ uint64_t PTIM_GetMicrotime(void) } vPortExitCritical(); - return (uint64_t)uwMillis*1000 + uwMicros; + return (uint64_t) uwMillis * 1000 + uwMicros; } /** microsecond delay */ void PTIM_MicroDelay(uint16_t usec) { - usec++; // rounding up assert_param(usec < 1000); - uint16_t end = (uint16_t) (TIMEBASE_TIMER->CNT + usec); - if (end > 999) end -= 1000; + const uint16_t start = (uint16_t) TIMEBASE_TIMER->CNT; + const uint16_t remain = (uint16_t) (999 - start); - while (TIMEBASE_TIMER->CNT != end); + if (remain > usec) { + // timer still has enough space going forward to pass the required wait time + for (; TIMEBASE_TIMER->CNT < start + usec;); + } + else { + // timer is too close to the end + usec -= remain; + for (; TIMEBASE_TIMER->CNT >= start || TIMEBASE_TIMER->CNT < usec;); + } } diff --git a/units/1wire/_ow_commands.h b/units/1wire/_ow_commands.h new file mode 100644 index 0000000..4270bde --- /dev/null +++ b/units/1wire/_ow_commands.h @@ -0,0 +1,25 @@ +// +// Created by MightyPork on 2018/01/29. +// + +#ifndef GEX_F072_OW_COMMANDS_H +#define GEX_F072_OW_COMMANDS_H + +#ifndef OW_INTERNAL +#error bad include! +#endif + +#define OW_ROM_SEARCH 0xF0 +#define OW_ROM_READ 0x33 +#define OW_ROM_MATCH 0x55 +#define OW_ROM_SKIP 0xCC +#define OW_ROM_ALM_SEARCH 0xEC + +#define OW_DS1820_CONVERT_T 0x44 +#define OW_DS1820_WRITE_SCRATCH 0x4E +#define OW_DS1820_READ_SCRATCH 0xBE +#define OW_DS1820_COPY_SCRATCH 0x48 +#define OW_DS1820_RECALL_E2 0xB8 +#define OW_DS1820_READ_SUPPLY 0xB4 + +#endif //GEX_F072_OW_COMMANDS_H diff --git a/units/1wire/_ow_internal.h b/units/1wire/_ow_internal.h new file mode 100644 index 0000000..7545d00 --- /dev/null +++ b/units/1wire/_ow_internal.h @@ -0,0 +1,80 @@ +// +// Created by MightyPork on 2018/01/29. +// + +#ifndef GEX_F072_OW_INTERNAL_H +#define GEX_F072_OW_INTERNAL_H + +#ifndef OW_INTERNAL +#error bad include! +#endif + +#include "_ow_commands.h" + +/** Private data structure */ +struct priv { + char port_name; + uint8_t pin_number; + + GPIO_TypeDef *port; + uint32_t ll_pin; +}; + +// Prototypes + +/** + * Reset the 1-wire bus + */ +bool ow_reset(Unit *unit); + +/** + * Write a bit to the 1-wire bus + */ +void ow_write_bit(Unit *unit, bool bit); + +/** + * Read a bit from the 1-wire bus + */ +bool ow_read_bit(Unit *unit); + +/** + * Write a byte to the 1-wire bus + */ +void ow_write_u8(Unit *unit, uint8_t byte); + +/** + * Write a halfword to the 1-wire bus + */ +void ow_write_u16(Unit *unit, uint16_t halfword); + +/** + * Write a word to the 1-wire bus + */ +void ow_write_u32(Unit *unit, uint32_t word); + +/** + * Write a doubleword to the 1-wire bus + */ +void ow_write_u64(Unit *unit, uint64_t dword); + +/** + * Read a byte form the 1-wire bus + */ +uint8_t ow_read_u8(Unit *unit); + +/** + * Read a halfword form the 1-wire bus + */ +uint16_t ow_read_u16(Unit *unit); + +/** + * Read a word form the 1-wire bus + */ +uint32_t ow_read_u32(Unit *unit); + +/** + * Read a doubleword form the 1-wire bus + */ +uint64_t ow_read_u64(Unit *unit); + +#endif //GEX_F072_OW_INTERNAL_H diff --git a/units/1wire/_ow_ll.c b/units/1wire/_ow_ll.c new file mode 100644 index 0000000..4e7913e --- /dev/null +++ b/units/1wire/_ow_ll.c @@ -0,0 +1,193 @@ +// +// Created by MightyPork on 2018/01/29. +// +// 1-Wire unit low level functions +// + +#include "platform.h" +#include "unit_base.h" + +#define OW_INTERNAL +#include "_ow_internal.h" + +static inline void ow_pull_high(Unit *unit) +{ + struct priv *priv = unit->data; + LL_GPIO_SetOutputPin(priv->port, priv->ll_pin); + LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); +} + +static inline void ow_pull_low(Unit *unit) +{ + struct priv *priv = unit->data; + LL_GPIO_ResetOutputPin(priv->port, priv->ll_pin); + LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); +} + +static inline void ow_release_line(Unit *unit) +{ + struct priv *priv = unit->data; + LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_INPUT); +} + +static inline bool ow_sample_line(Unit *unit) +{ + struct priv *priv = unit->data; + return (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin); +} + +/** + * Reset the 1-wire bus + */ +bool ow_reset(Unit *unit) +{ + ow_pull_low(unit); + PTIM_MicroDelay(500); + + bool presence; + vPortEnterCritical(); + { + // Strong pull-up (for parasitive power) + ow_pull_high(unit); + PTIM_MicroDelay(2); + + // switch to open-drain + ow_release_line(unit); + PTIM_MicroDelay(118); + + presence = !ow_sample_line(unit); + } + vPortExitCritical(); + + PTIM_MicroDelay(130); + return presence; +} + +/** + * Write a bit to the 1-wire bus + */ +void ow_write_bit(Unit *unit, bool bit) +{ + vPortEnterCritical(); + { + // start mark + ow_pull_low(unit); + PTIM_MicroDelay(2); + + if (bit) ow_pull_high(unit); + PTIM_MicroDelay(70); + + // Strong pull-up (for parasitive power) + ow_pull_high(unit); + } + vPortExitCritical(); + + PTIM_MicroDelay(2); +} + +/** + * Read a bit from the 1-wire bus + */ +bool ow_read_bit(Unit *unit) +{ + bool bit; + + vPortEnterCritical(); + { + // start mark + ow_pull_low(unit); + PTIM_MicroDelay(2); + + ow_release_line(unit); + PTIM_MicroDelay(20); + + bit = ow_sample_line(unit); + } + vPortExitCritical(); + + PTIM_MicroDelay(40); + + return bit; +} + +/** + * Write a byte to the 1-wire bus + */ +void ow_write_u8(Unit *unit, uint8_t byte) +{ + for (int i = 0; i < 8; i++) { + ow_write_bit(unit, 0 != (byte & (1 << i))); + } +} + +/** + * Write a halfword to the 1-wire bus + */ +void ow_write_u16(Unit *unit, uint16_t halfword) +{ + ow_write_u8(unit, (uint8_t) (halfword & 0xFF)); + ow_write_u8(unit, (uint8_t) ((halfword >> 8) & 0xFF)); +} + +/** + * Write a word to the 1-wire bus + */ +void ow_write_u32(Unit *unit, uint32_t word) +{ + ow_write_u16(unit, (uint16_t) (word)); + ow_write_u16(unit, (uint16_t) (word >> 16)); +} + +/** + * Write a doubleword to the 1-wire bus + */ +void ow_write_u64(Unit *unit, uint64_t dword) +{ + ow_write_u32(unit, (uint32_t) (dword)); + ow_write_u32(unit, (uint32_t) (dword >> 32)); +} + +/** + * Read a byte form the 1-wire bus + */ +uint8_t ow_read_u8(Unit *unit) +{ + uint8_t buf = 0; + for (int i = 0; i < 8; i++) { + buf |= (1 & ow_read_bit(unit)) << i; + } + return buf; +} + +/** + * Read a halfword form the 1-wire bus + */ +uint16_t ow_read_u16(Unit *unit) +{ + uint16_t acu = 0; + acu |= ow_read_u8(unit); + acu |= ow_read_u8(unit) << 8; + return acu; +} + +/** + * Read a word form the 1-wire bus + */ +uint32_t ow_read_u32(Unit *unit) +{ + uint32_t acu = 0; + acu |= ow_read_u16(unit); + acu |= (uint32_t)ow_read_u16(unit) << 16; + return acu; +} + +/** + * Read a doubleword form the 1-wire bus + */ +uint64_t ow_read_u64(Unit *unit) +{ + uint64_t acu = 0; + acu |= ow_read_u32(unit); + acu |= (uint64_t)ow_read_u32(unit) << 32; + return acu; +} diff --git a/units/1wire/unit_1wire.c b/units/1wire/unit_1wire.c index 6a13fc2..05b7d38 100644 --- a/units/1wire/unit_1wire.c +++ b/units/1wire/unit_1wire.c @@ -8,15 +8,8 @@ #include "unit_1wire.h" // 1WIRE master - -/** Private data structure */ -struct priv { - char port_name; - uint8_t pin_number; - - GPIO_TypeDef *port; - uint32_t ll_pin; -}; +#define OW_INTERNAL +#include "_ow_internal.h" // ------------------------------------------------------------------------ @@ -124,206 +117,6 @@ static void U1WIRE_deInit(Unit *unit) // ------------------------------------------------------------------------ -static inline void ow_pull_high(Unit *unit) -{ - struct priv *priv = unit->data; - LL_GPIO_SetOutputPin(priv->port, priv->ll_pin); - LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); -} - -static inline void ow_pull_low(Unit *unit) -{ - struct priv *priv = unit->data; - LL_GPIO_ResetOutputPin(priv->port, priv->ll_pin); - LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_OUTPUT); -} - -static inline void ow_release_line(Unit *unit) -{ - struct priv *priv = unit->data; - LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_INPUT); -} - -static inline bool ow_sample_line(Unit *unit) -{ - struct priv *priv = unit->data; - return (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin); -} - - -/** - * Reset the 1-wire bus - */ -static bool ow_reset(Unit *unit) -{ - ow_pull_low(unit); - PTIM_MicroDelay(500); - - bool presence; - - vPortEnterCritical(); - { - // Strong pull-up (for parasitive power) - ow_pull_high(unit); - PTIM_MicroDelay(2); - - // switch to open-drain - ow_release_line(unit); - PTIM_MicroDelay(118); - - presence = !ow_sample_line(unit); - } - vPortExitCritical(); - - PTIM_MicroDelay(130); - return presence; -} - -/** - * Write a bit to the 1-wire bus - */ -static void ow_write(Unit *unit, bool bit) -{ - vPortEnterCritical(); - { - // start mark - ow_pull_low(unit); - PTIM_MicroDelay(2); - - if (bit) ow_pull_high(unit); - PTIM_MicroDelay(70); - - // Strong pull-up (for parasitive power) - ow_pull_high(unit); - } - vPortExitCritical(); - - PTIM_MicroDelay(2); -} - -/** - * Read a bit from the 1-wire bus - */ -static bool ow_read(Unit *unit) -{ - bool bit; - - vPortEnterCritical(); - { - // start mark - ow_pull_low(unit); - PTIM_MicroDelay(2); - - ow_release_line(unit); - PTIM_MicroDelay(20); - - bit = ow_sample_line(unit); - } - vPortExitCritical(); - - PTIM_MicroDelay(40); - - return bit; -} - -/** - * Write a byte to the 1-wire bus - */ -static void ow_write_u8(Unit *unit, uint8_t byte) -{ - for (int i = 0; i < 8; i++) { - ow_write(unit, 0 != (byte & (1 << i))); - } -} - -/** - * Write a halfword to the 1-wire bus - */ -static void ow_write_u16(Unit *unit, uint16_t halfword) -{ - ow_write_u8(unit, (uint8_t) (halfword & 0xFF)); - ow_write_u8(unit, (uint8_t) ((halfword >> 8) & 0xFF)); -} - -/** - * Write a word to the 1-wire bus - */ -static void ow_write_u32(Unit *unit, uint32_t word) -{ - ow_write_u16(unit, (uint16_t) (word)); - ow_write_u16(unit, (uint16_t) (word >> 16)); -} - -/** - * Write a doubleword to the 1-wire bus - */ -static void ow_write_u64(Unit *unit, uint64_t dword) -{ - ow_write_u32(unit, (uint32_t) (dword)); - ow_write_u32(unit, (uint32_t) (dword >> 32)); -} - -/** - * Read a byte form the 1-wire bus - */ -static uint8_t ow_read_u8(Unit *unit) -{ - uint8_t buf = 0; - for (int i = 0; i < 8; i++) { - buf <<= 1; - buf |= 1 & ow_read(unit); - } - return buf; -} - -/** - * Read a halfword form the 1-wire bus - */ -static uint16_t ow_read_u16(Unit *unit) -{ - uint16_t acu = 0; - acu |= ow_read_u8(unit); - acu |= ow_read_u8(unit) << 8; - return acu; -} - -/** - * Read a word form the 1-wire bus - */ -static uint32_t ow_read_u32(Unit *unit) -{ - uint32_t acu = 0; - acu |= ow_read_u16(unit); - acu |= (uint32_t)ow_read_u16(unit) << 16; - return acu; -} - -/** - * Read a doubleword form the 1-wire bus - */ -static uint64_t ow_read_u64(Unit *unit) -{ - uint64_t acu = 0; - acu |= ow_read_u32(unit); - acu |= (uint64_t)ow_read_u32(unit) << 32; - return acu; -} - -// ------------------------------------------------------------------------ - -#define OW_ROM_SEARCH 0xF0 -#define OW_ROM_READ 0x33 -#define OW_ROM_MATCH 0x55 -#define OW_ROM_SKIP 0xCC -#define OW_ROM_ALM_SEARCH 0xEC - -#define OW_DS1820_CONVERT_T 0x44 -#define OW_DS1820_WRITE_SCRATCH 0x4E -#define OW_DS1820_READ_SCRATCH 0xBE -#define OW_DS1820_COPY_SCRATCH 0x48 -#define OW_DS1820_RECALL_E2 0xB8 -#define OW_DS1820_READ_SUPPLY 0xB4 - enum PinCmd_ { CMD_TEST = 0, }; @@ -336,17 +129,20 @@ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, case CMD_TEST:; bool presence = ow_reset(unit); if (!presence) return E_HW_TIMEOUT; + ow_write_u8(unit, OW_ROM_SKIP); + ow_write_u8(unit, OW_DS1820_CONVERT_T); - ow_pull_high(unit); + while (!ow_read_bit(unit)); - osDelay(750); + // osDelay(750); // TODO this will be done with an async timer // If parasitive power is not used, we could poll and check the status bit presence = ow_reset(unit); if (!presence) return E_HW_TIMEOUT; ow_write_u8(unit, OW_ROM_SKIP); + ow_write_u8(unit, OW_DS1820_READ_SCRATCH); uint16_t temp = ow_read_u16(unit); @@ -362,6 +158,7 @@ static error_t U1WIRE_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, pb_u8(&pb, cnt_remain); pb_u8(&pb, cnt_per_c); + dbg("respond ..."); com_respond_buf(frame_id, MSG_SUCCESS, pb.start, pb_length(&pb)); return E_SUCCESS;