From 9cff75554b4d2787c1cc2183be36db0da84e7107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 16 Feb 2018 16:10:18 +0100 Subject: [PATCH] sipo implemented --- gex.mk | 1 + platform/hw_utils.c | 5 +- platform/platform.c | 2 + units/sipo/_sipo_api.c | 94 +++++++++++++++++++++++++++++++++++++ units/sipo/_sipo_init.c | 3 ++ units/sipo/_sipo_internal.h | 50 ++++++++++++++++++++ units/sipo/_sipo_settings.c | 10 ++-- units/sipo/unit_sipo.c | 80 +++++++++++-------------------- 8 files changed, 186 insertions(+), 59 deletions(-) diff --git a/gex.mk b/gex.mk index 94a9543..922d0d6 100644 --- a/gex.mk +++ b/gex.mk @@ -14,6 +14,7 @@ GEX_SRC_DIR = \ User/units/i2c \ User/units/spi \ User/units/adc \ + User/units/sipo \ User/TinyFrame \ User/CWPack \ User/tasks diff --git a/platform/hw_utils.c b/platform/hw_utils.c index 7619775..8c9c3f5 100644 --- a/platform/hw_utils.c +++ b/platform/hw_utils.c @@ -240,6 +240,8 @@ char * pinmask2str_up(uint32_t pins, char *buffer) return buffer; } +#pragma GCC push_options +#pragma GCC optimize ("O2") /** spread a packed pinfield using a mask */ uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask) { @@ -247,7 +249,7 @@ uint32_t pinmask_spread_32(uint32_t packed, uint32_t mask) uint32_t poke = 1; if(packed == 0) return 0; - for (int i = 0; i<32; i++) { + for (int i = 0; i < 32; i++) { if (mask & 1) { if (packed & poke) { result |= 1<data; + + if (buflen % priv->data_width != 0) { + dbg("Buflen %d vs width %d", (int)buflen, (int)priv->data_width); + return E_BAD_COUNT; // must be a multiple of the channel count + } + + // buffer contains data for the individual data pins, back to back as AAA BBB CCC (whole bytes) + const uint8_t data_width = priv->data_width; + const uint16_t bytelen = buflen / data_width; + const uint16_t mask = priv->data_pins; + + uint8_t offsets[16]; + for (int i=0; i<16; i++) offsets[i] = (uint8_t) (bytelen * i); + + for (int32_t bn = bytelen - 1; bn >= 0; bn--) { + // send the byte + for (int32_t i = 0; i < 8; i++) { + uint16_t packed = 0; + for (int32_t j = data_width - 1; j >= 0; j--) { + packed |= (buffer[bn + offsets[j]] >> i) & 1; + if (j > 0) packed <<= 1; + } + + uint16_t spread = pinmask_spread(packed, mask); + priv->data_port->BSRR = spread | (((~spread) & mask) << 16); + + // Shift clock pulse + send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll); + } + } + + send_pulse(priv->store_pol, priv->store_port, priv->store_ll); + return E_SUCCESS; +} +#pragma GCC pop_options + +error_t UU_SIPO_DirectData(Unit *unit, uint16_t data_packed) +{ + CHECK_TYPE(unit, &UNIT_SIPO); + struct priv *priv = unit->data; + + uint16_t spread = pinmask_spread(data_packed, priv->data_pins); + priv->data_port->BSRR = spread | (((~spread) & priv->data_pins) << 16); + return E_SUCCESS; +} + +error_t UU_SIPO_DirectClear(Unit *unit) +{ + CHECK_TYPE(unit, &UNIT_SIPO); + struct priv *priv = unit->data; + send_pulse(priv->clear_pol, priv->clear_port, priv->clear_ll); + return E_SUCCESS; +} + +error_t UU_SIPO_DirectShift(Unit *unit) +{ + CHECK_TYPE(unit, &UNIT_SIPO); + struct priv *priv = unit->data; + send_pulse(priv->shift_pol, priv->shift_port, priv->shift_ll); + return E_SUCCESS; +} + +error_t UU_SIPO_DirectStore(Unit *unit) +{ + CHECK_TYPE(unit, &UNIT_SIPO); + struct priv *priv = unit->data; + send_pulse(priv->store_pol, priv->store_port, priv->store_ll); + return E_SUCCESS; +} diff --git a/units/sipo/_sipo_init.c b/units/sipo/_sipo_init.c index 337f6b9..ed0db40 100644 --- a/units/sipo/_sipo_init.c +++ b/units/sipo/_sipo_init.c @@ -108,6 +108,9 @@ error_t USIPO_init(Unit *unit) else LL_GPIO_SetOutputPin(priv->clear_port, priv->clear_ll); + // initial clear + UU_SIPO_DirectClear(unit); + return E_SUCCESS; } diff --git a/units/sipo/_sipo_internal.h b/units/sipo/_sipo_internal.h index 3db7808..28b5c2e 100644 --- a/units/sipo/_sipo_internal.h +++ b/units/sipo/_sipo_internal.h @@ -67,4 +67,54 @@ error_t USIPO_init(Unit *unit); /** Tear down the unit */ void USIPO_deInit(Unit *unit); +// ------------------------------------------------------------------------ + +/** + * Write a buffer to the pins. + * Buffer contains data for the individual channels, sequentially (AAAAAA BBBBBB CCCCCC ...) + * The bytes are sent LSB first, from the last byte (e.g. 1,2,3 - 3 is sent first, LSB-first). + * + * The chunks order is from the lowest to the highest bit + * + * @param unit + * @param buffer - buffer of data to send + * @param buflen - number of bytes in the buffer + * @return success + */ +error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen); + +/** + * Direct access to the output data pins (may be useful for debugging, or circuits that use them + * for something else when not loading a new value). + * + * @param unit + * @param data_packed - packed data to set on the output (right-aligned, highest to lowest pin) + * @return success + */ +error_t UU_SIPO_DirectData(Unit *unit, uint16_t data_packed); + +/** + * Send a clear pulse. + * + * @param unit + * @return success + */ +error_t UU_SIPO_DirectClear(Unit *unit); + +/** + * Send a shift pulse. + * + * @param unit + * @return success + */ +error_t UU_SIPO_DirectShift(Unit *unit); + +/** + * Send a store pulse. + * + * @param unit + * @return success + */ +error_t UU_SIPO_DirectStore(Unit *unit); + #endif //GEX_F072_SIPO_INTERNAL_H diff --git a/units/sipo/_sipo_settings.c b/units/sipo/_sipo_settings.c index 897928f..fcd6343 100644 --- a/units/sipo/_sipo_settings.c +++ b/units/sipo/_sipo_settings.c @@ -103,20 +103,20 @@ void USIPO_writeIni(Unit *unit, IniWriter *iw) { struct priv *priv = unit->data; - iw_comment(iw, "Store pin & its active edge (1-rising,0-falling)"); - iw_entry(iw, "store-pin", "%c%d", priv->store_pname, priv->store_pnum); - iw_entry(iw, "store-pol", "%d", priv->store_pol); - iw_comment(iw, "Shift pin & its active edge"); iw_entry(iw, "shift-pin", "%c%d", priv->shift_pname, priv->shift_pnum); iw_entry(iw, "shift-pol", "%d", priv->shift_pol); + iw_comment(iw, "Store pin & its active edge (1-rising,0-falling)"); + iw_entry(iw, "store-pin", "%c%d", priv->store_pname, priv->store_pnum); + iw_entry(iw, "store-pol", "%d", priv->store_pol); + iw_comment(iw, "Clear pin & its active level"); iw_entry(iw, "clear-pin", "%c%d", priv->clear_pname, priv->clear_pnum); iw_entry(iw, "clear-pol", "%d", priv->clear_pol); iw_comment(iw, "Data port and pins"); iw_entry(iw, "data-port", "%c", priv->data_pname); - iw_entry(iw, "data-pins", "%s", pinmask2str(priv->data_pins, unit_tmp512)); + iw_entry(iw, "data-pins", "%s", pinmask2str_up(priv->data_pins, unit_tmp512)); } diff --git a/units/sipo/unit_sipo.c b/units/sipo/unit_sipo.c index 74aead0..a96d900 100644 --- a/units/sipo/unit_sipo.c +++ b/units/sipo/unit_sipo.c @@ -9,68 +9,42 @@ #include "_sipo_internal.h" -error_t UU_SIPO_Write(Unit *unit, const uint8_t *buffer, uint16_t buflen) -{ - struct priv *priv = unit->data; - - if (buflen % priv->data_width != 0) { - return E_BAD_COUNT; // must be a multiple of the channel count - } - - // buffer contains data for the individual data pins, back to back as AAA BBB CCC (whole bytes) - - const uint16_t bytelen = buflen / priv->data_width; - - for (int bn = 0; bn < bytelen; bn--) { - // send the byte - for (int i = 0; i < 8; i++) { - uint16_t packed = 0; - - for (int j = 0; j < priv->data_width; j++) { - packed |= (bool) (buffer[bn + j * bytelen] & (1 << i)); - packed <<= 1; - } - - uint16_t spread = pinmask_spread(packed, priv->data_pins); - uint16_t set = spread; - uint16_t reset = ((~spread) & priv->data_pins); - priv->data_port->BSRR = set | (reset << 16); - - if (priv->shift_pol) { - LL_GPIO_SetOutputPin(priv->shift_port, priv->shift_ll); - LL_GPIO_ResetOutputPin(priv->shift_port, priv->shift_ll); - } - else { - LL_GPIO_ResetOutputPin(priv->shift_port, priv->shift_ll); - LL_GPIO_SetOutputPin(priv->shift_port, priv->shift_ll); - } - } - } - - if (priv->store_pol) { - LL_GPIO_SetOutputPin(priv->store_port, priv->store_ll); - LL_GPIO_ResetOutputPin(priv->store_port, priv->store_ll); - } - else { - LL_GPIO_ResetOutputPin(priv->store_port, priv->store_ll); - LL_GPIO_SetOutputPin(priv->store_port, priv->store_ll); - } -} - // ------------------------------------------------------------------------ enum SipoCmd_ { - CMD_WRITE, + CMD_WRITE = 0, + CMD_DIRECT_DATA = 1, + CMD_DIRECT_SHIFT = 2, + CMD_DIRECT_CLEAR = 3, + CMD_DIRECT_STORE = 4, }; /** Handle a request message */ static error_t USIPO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { switch (command) { - case CMD_WRITE:; - uint32_t len; - const uint8_t *tail = pp_tail(pp, &len); - UU_SIPO_Write(unit, (uint8_t *) tail, (uint16_t) len); + case CMD_WRITE: + { + uint32_t len; + const uint8_t *tail = pp_tail(pp, &len); + TRY(UU_SIPO_Write(unit, (uint8_t *) tail, (uint16_t) len)); + } + return E_SUCCESS; + + case CMD_DIRECT_DATA: + TRY(UU_SIPO_DirectData(unit, pp_u16(pp))); + return E_SUCCESS; + + case CMD_DIRECT_CLEAR: + TRY(UU_SIPO_DirectClear(unit)); + return E_SUCCESS; + + case CMD_DIRECT_SHIFT: + TRY(UU_SIPO_DirectShift(unit)); + return E_SUCCESS; + + case CMD_DIRECT_STORE: + TRY(UU_SIPO_DirectStore(unit)); return E_SUCCESS; default: