pulse generation for digital out

dac
Ondřej Hruška 7 years ago
parent 274f2be6e0
commit 590d550a09
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 27
      platform/timebase.c
  2. 22
      platform/timebase.h
  3. 4
      units/1wire/unit_1wire.c
  4. 106
      units/digital_out/_dout_api.c
  5. 5
      units/digital_out/_dout_internal.h
  6. 12
      units/digital_out/unit_dout.c
  7. 12
      units/digital_out/unit_dout.h
  8. 4
      units/i2c/unit_i2c.c
  9. 4
      units/sipo/unit_sipo.c
  10. 4
      units/spi/unit_spi.c
  11. 4
      units/usart/unit_usart.c

@ -7,8 +7,6 @@
// ---------------------------- HAL TIMEBASE ----------------------------- // ---------------------------- HAL TIMEBASE -----------------------------
#define TIMEBASE_TIMER TIM17
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{ {
// EDIT - used 17 instead because 14 was needed for fcap // EDIT - used 17 instead because 14 was needed for fcap
@ -102,21 +100,36 @@ uint64_t PTIM_GetMicrotime(void)
return (uint64_t) uwMillis * 1000 + uwMicros; return (uint64_t) uwMillis * 1000 + uwMicros;
} }
/** microsecond delay */ /** microsecond delay */
void PTIM_MicroDelay(uint16_t usec) void PTIM_MicroDelayAligned(uint32_t usec, register const uint32_t start)
{ {
assert_param(usec < 1000); assert_param(usec < 1000);
const uint16_t start = (uint16_t) TIMEBASE_TIMER->CNT; register const uint32_t remain = (1000 - start);
const uint16_t remain = (uint16_t) (999 - start);
if (remain > usec) { if (remain > usec) {
// timer still has enough space going forward to pass the required wait time // timer still has enough space going forward to pass the required wait time
for (; TIMEBASE_TIMER->CNT < start + usec;); register const uint32_t end = start + usec;
while (TIMEBASE_TIMER->CNT < end) {
__NOP();
__NOP();
__NOP();
}
return;
} }
else { else {
// timer is too close to the end // timer is too close to the end
usec -= remain; usec -= remain;
for (; TIMEBASE_TIMER->CNT >= start || TIMEBASE_TIMER->CNT < usec;); while (1) {
register const uint32_t t = TIMEBASE_TIMER->CNT;
if (t < start && t >= usec) return;
}
} }
} }
/** microsecond delay */
void PTIM_MicroDelay(const uint32_t usec)
{
PTIM_MicroDelayAligned(usec, TIMEBASE_TIMER->CNT);
}

@ -13,6 +13,8 @@
#include "platform.h" #include "platform.h"
#define TIMEBASE_TIMER TIM17
/** /**
* Precision timer: get microtime as uint64_t * Precision timer: get microtime as uint64_t
* This timestamp should be monotonously increasing with a precision of ±0.5µs * This timestamp should be monotonously increasing with a precision of ±0.5µs
@ -36,6 +38,24 @@ static inline uint32_t PTIM_GetTime(void)
* *
* @param usec - max 998 * @param usec - max 998
*/ */
void PTIM_MicroDelay(uint16_t usec); void PTIM_MicroDelay(uint32_t usec);
/**
* Microsecond busy delay with alignment (reduced length jitter but possible up to 1 us delay)
*
* @param usec
*/
void PTIM_MicroDelayAligned(uint32_t usec, uint32_t start);
/**
* Wait until the next micro timer tick
*/
static inline uint32_t PTIM_MicroDelayAlign(void)
{
const uint32_t c = TIMEBASE_TIMER->CNT;
uint32_t res;
while ((res = TIMEBASE_TIMER->CNT) == c);
return res;
}
#endif //GEX_F072_TIMEBASE_H #endif //GEX_F072_TIMEBASE_H

@ -89,7 +89,7 @@ enum PinCmd_ {
CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices CMD_SEARCH_CONTINUE = 3, // continue the previously started scan, retrieving more devices
CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus) CMD_READ_ADDR = 4, // read the ROM code from a single device (for single-device bus)
CMD_WRITE = 10, // write multiple bytes using the SKIP_ROM command CMD_QUERY = 10, // write multiple bytes using the SKIP_ROM command
CMD_READ = 11, // write multiple bytes using a ROM address CMD_READ = 11, // write multiple bytes using a ROM address
CMD_POLL_FOR_1 = 20, CMD_POLL_FOR_1 = 20,
@ -194,7 +194,7 @@ static error_t OW_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay
* addr:u64, rest:write_data * addr:u64, rest:write_data
* if addr is 0, use SKIP_ROM * if addr is 0, use SKIP_ROM
*/ */
case CMD_WRITE: case CMD_QUERY:
addr = pp_u64(pp); addr = pp_u64(pp);
tail = pp_tail(pp, &remain); tail = pp_tail(pp, &remain);
TRY(UU_1WIRE_Write(unit, addr, tail, remain)); TRY(UU_1WIRE_Write(unit, addr, tail, remain));

@ -7,8 +7,20 @@
#include "unit_dout.h" #include "unit_dout.h"
#define DOUT_INTERNAL #define DOUT_INTERNAL
#include "_dout_internal.h" #include "_dout_internal.h"
static void clear_pulse_by_mask(struct priv *priv, uint16_t spread)
{
assert_param(priv);
for (int i = 0; i < 16; i++) {
if (spread & (1 << i)) {
priv->msec_pulse_cnt[i] = 0;
}
}
}
error_t UU_DOut_Write(Unit *unit, uint16_t packed) error_t UU_DOut_Write(Unit *unit, uint16_t packed)
{ {
CHECK_TYPE(unit, &UNIT_DOUT); CHECK_TYPE(unit, &UNIT_DOUT);
@ -16,6 +28,7 @@ error_t UU_DOut_Write(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
uint16_t set = spread; uint16_t set = spread;
uint16_t reset = ((~spread) & mask); uint16_t reset = ((~spread) & mask);
@ -30,6 +43,7 @@ error_t UU_DOut_Set(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
priv->port->BSRR = spread; priv->port->BSRR = spread;
return E_SUCCESS; return E_SUCCESS;
@ -42,8 +56,9 @@ error_t UU_DOut_Clear(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
priv->port->BSRR = (spread<<16); priv->port->BSRR = (spread << 16);
return E_SUCCESS; return E_SUCCESS;
} }
@ -54,11 +69,12 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint16_t mask = priv->pins; uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask); uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask; uint16_t flipped = (uint16_t) (~priv->port->ODR) & mask;
uint16_t set = flipped & spread; uint16_t set = flipped & spread;
uint16_t reset = ((~flipped) & mask) & spread; uint16_t reset = ((~flipped) & mask) & spread;
priv->port->BSRR = set | (reset<<16); priv->port->BSRR = set | (reset << 16);
return E_SUCCESS; return E_SUCCESS;
} }
@ -68,6 +84,90 @@ error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count)
struct priv *priv = unit->data; struct priv *priv = unit->data;
uint32_t packed = pinmask_pack(0xFFFF, priv->pins); uint32_t packed = pinmask_pack(0xFFFF, priv->pins);
*count = (uint8_t)(32 - __CLZ(packed)); *count = (uint8_t) (32 - __CLZ(packed));
return E_SUCCESS; return E_SUCCESS;
} }
error_t UU_DOut_Pulse(Unit *unit, uint16_t packed, bool polarity, bool is_usec, uint16_t count)
{
CHECK_TYPE(unit, &UNIT_DOUT);
struct priv *priv = unit->data;
assert_param(priv);
uint16_t mask = priv->pins;
uint16_t spread = pinmask_spread(packed, mask);
clear_pulse_by_mask(priv, spread);
vPortEnterCritical();
if (is_usec) {
// we're gonna do this right here as a delay loop.
if (count >= 1000) {
// too long, fall back to msec
count /= 1000;
is_usec = false;
}
else {
const uint32_t bsrr1 = spread << (polarity ? 0 : 16);
const uint32_t bsrr0 = spread << (polarity ? 16 : 0);
const uint32_t start = PTIM_MicroDelayAlign();
priv->port->BSRR = bsrr1;
PTIM_MicroDelayAligned(count, start);
priv->port->BSRR = bsrr0;
}
}
if (!is_usec) {
// Load the counters
for (int i = 0; i < 16; i++) {
if (spread & (1 << i)) {
priv->msec_pulse_cnt[i] = (uint16_t) (count + 1);
}
}
if (polarity) {
priv->msec_pulse_scheduled_1 |= spread;
} else {
priv->msec_pulse_scheduled_0 |= spread;
}
unit->_tick_cnt = 0;
unit->tick_interval = 1;
}
vPortExitCritical();
return E_SUCCESS;
}
void DOut_Tick(Unit *unit)
{
struct priv *priv = unit->data;
uint16_t odr = (uint16_t) priv->port->ODR;
int live_cnt = 0;
for (int i = 0; i < 16; i++) {
if (priv->msec_pulse_scheduled_1 & (1<<i)) {
odr |= (1<<i);
} else if (priv->msec_pulse_scheduled_0 & (1<<i)) {
odr &= ~(1<<i);
}
if (priv->msec_pulse_cnt[i] > 0) {
live_cnt++;
priv->msec_pulse_cnt[i]--;
if (priv->msec_pulse_cnt[i] == 0) {
odr ^= 1 << i;
}
}
}
priv->port->ODR = odr;
priv->msec_pulse_scheduled_1 = 0;
priv->msec_pulse_scheduled_0 = 0;
if (live_cnt == 0) {
unit->_tick_cnt = 0;
unit->tick_interval = 0;
}
}

@ -19,6 +19,9 @@ struct priv {
uint16_t open_drain; // open drain pins uint16_t open_drain; // open drain pins
GPIO_TypeDef *port; GPIO_TypeDef *port;
uint16_t msec_pulse_cnt[16];
uint16_t msec_pulse_scheduled_1;
uint16_t msec_pulse_scheduled_0;
}; };
/** Allocate data structure and set defaults */ /** Allocate data structure and set defaults */
@ -46,4 +49,6 @@ error_t DOut_init(Unit *unit);
/** Tear down the unit */ /** Tear down the unit */
void DOut_deInit(Unit *unit); void DOut_deInit(Unit *unit);
void DOut_Tick(Unit *unit);
#endif //GEX_F072_DOUT_INTERNAL_H #endif //GEX_F072_DOUT_INTERNAL_H

@ -9,10 +9,11 @@
#include "_dout_internal.h" #include "_dout_internal.h"
enum PinCmd_ { enum PinCmd_ {
CMD_TEST = 0, CMD_QUERY = 0,
CMD_SET = 1, CMD_SET = 1,
CMD_CLEAR = 2, CMD_CLEAR = 2,
CMD_TOGGLE = 3, CMD_TOGGLE = 3,
CMD_PULSE = 4,
}; };
/** Handle a request message */ /** Handle a request message */
@ -21,7 +22,7 @@ static error_t DOut_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
uint16_t packed = pp_u16(pp); uint16_t packed = pp_u16(pp);
switch (command) { switch (command) {
case CMD_TEST: case CMD_QUERY:
return UU_DOut_Write(unit, packed); return UU_DOut_Write(unit, packed);
case CMD_SET: case CMD_SET:
@ -33,6 +34,12 @@ static error_t DOut_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
case CMD_TOGGLE: case CMD_TOGGLE:
return UU_DOut_Toggle(unit, packed); return UU_DOut_Toggle(unit, packed);
case CMD_PULSE:;
bool polarity = pp_bool(pp);
bool is_usec = pp_bool(pp);
uint16_t count = pp_u16(pp);
return UU_DOut_Pulse(unit, packed, polarity, is_usec, count);
default: default:
return E_UNKNOWN_COMMAND; return E_UNKNOWN_COMMAND;
} }
@ -55,4 +62,5 @@ const UnitDriver UNIT_DOUT = {
.deInit = DOut_deInit, .deInit = DOut_deInit,
// Function // Function
.handleRequest = DOut_handleRequest, .handleRequest = DOut_handleRequest,
.updateTick = DOut_Tick,
}; };

@ -56,4 +56,16 @@ error_t UU_DOut_Toggle(Unit *unit, uint16_t packed);
*/ */
error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count); error_t UU_DOut_GetPinCount(Unit *unit, uint8_t *count);
/**
* Send a pulse
*
* @param unit
* @param packed - pins to pulse
* @param polarity - pulse active level
* @param is_usec - use usec precision (for < 1 ms)
* @param count - number of units (msec or usec)
* @return success
*/
error_t UU_DOut_Pulse(Unit *unit, uint16_t packed, bool polarity, bool is_usec, uint16_t count);
#endif //U_DOUT_H #endif //U_DOUT_H

@ -12,7 +12,7 @@
#include "_i2c_internal.h" #include "_i2c_internal.h"
enum PinCmd_ { enum PinCmd_ {
CMD_TEST = 0, CMD_QUERY = 0,
CMD_READ = 1, CMD_READ = 1,
CMD_WRITE_REG = 2, CMD_WRITE_REG = 2,
CMD_READ_REG = 3, CMD_READ_REG = 3,
@ -30,7 +30,7 @@ static error_t UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
switch (command) { switch (command) {
/** Write byte(s) - addr:u16, byte(s) */ /** Write byte(s) - addr:u16, byte(s) */
case CMD_TEST: case CMD_QUERY:
addr = pp_u16(pp); addr = pp_u16(pp);
const uint8_t *bb = pp_tail(pp, &len); const uint8_t *bb = pp_tail(pp, &len);

@ -12,7 +12,7 @@
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
enum SipoCmd_ { enum SipoCmd_ {
CMD_WRITE = 0, CMD_QUERY = 0,
CMD_DIRECT_DATA = 1, CMD_DIRECT_DATA = 1,
CMD_DIRECT_SHIFT = 2, CMD_DIRECT_SHIFT = 2,
CMD_DIRECT_CLEAR = 3, CMD_DIRECT_CLEAR = 3,
@ -23,7 +23,7 @@ enum SipoCmd_ {
static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{ {
switch (command) { switch (command) {
case CMD_WRITE: case CMD_QUERY:
{ {
uint32_t len; uint32_t len;
uint16_t terminal_packed = pp_u16(pp); uint16_t terminal_packed = pp_u16(pp);

@ -15,7 +15,7 @@
// SPI master // SPI master
enum PinCmd_ { enum PinCmd_ {
CMD_TEST = 0, CMD_QUERY = 0,
CMD_MULTICAST = 1, CMD_MULTICAST = 1,
}; };
@ -33,7 +33,7 @@ static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P
switch (command) { switch (command) {
/** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */ /** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */
case CMD_TEST: case CMD_QUERY:
slave = pp_u8(pp); slave = pp_u8(pp);
resp_skip = pp_u16(pp); resp_skip = pp_u16(pp);
resp_len = pp_u16(pp); resp_len = pp_u16(pp);

@ -92,7 +92,7 @@ void UUSART_Tick(Unit *unit)
} }
enum PinCmd_ { enum PinCmd_ {
CMD_WRITE = 0, CMD_QUERY = 0,
CMD_WRITE_SYNC = 1, CMD_WRITE_SYNC = 1,
}; };
@ -103,7 +103,7 @@ static error_t UUSART_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command,
const uint8_t *pld; const uint8_t *pld;
switch (command) { switch (command) {
/** Write bytes to the USART. Payload consists of the data to send. Waits for completion. */ /** Write bytes to the USART. Payload consists of the data to send. Waits for completion. */
case CMD_WRITE: case CMD_QUERY:
pld = pp_tail(pp, &len); pld = pp_tail(pp, &len);
TRY(UU_USART_Write(unit, pld, len)); TRY(UU_USART_Write(unit, pld, len));
return E_SUCCESS; return E_SUCCESS;

Loading…
Cancel
Save