From 83c2f26c433d344bf6e65144f2937914f47dea01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 4 Jan 2018 23:58:53 +0100 Subject: [PATCH 01/13] w.i.p. SPI, left to add: pin mappings, UU functions --- units/digital_out/unit_dout.c | 13 +- units/digital_out/unit_dout.h | 10 + units/i2c/unit_i2c.c | 20 +- units/spi/unit_spi.c | 399 ++++++++++++++++++++++++++++++++++ units/spi/unit_spi.h | 48 ++++ 5 files changed, 478 insertions(+), 12 deletions(-) create mode 100644 units/spi/unit_spi.c create mode 100644 units/spi/unit_spi.h diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index a573208..cb6f48d 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -62,7 +62,7 @@ static error_t DO_loadIni(Unit *unit, const char *key, const char *value) else if (streq(key, "initial")) { priv->initial = parse_pinmask(value, &suc); } - else if (streq(key, "opendrain")) { + else if (streq(key, "open-drain")) { priv->open_drain = parse_pinmask(value, &suc); } else { @@ -88,7 +88,7 @@ static void DO_writeIni(Unit *unit, IniWriter *iw) iw_entry(iw, "initial", "%s", str_pinmask(priv->initial, unit_tmp512)); iw_comment(iw, "Open-drain pins"); - iw_entry(iw, "opendrain", "%s", str_pinmask(priv->open_drain, unit_tmp512)); + iw_entry(iw, "open-drain", "%s", str_pinmask(priv->open_drain, unit_tmp512)); } // ------------------------------------------------------------------------ @@ -234,6 +234,15 @@ error_t UU_DO_Toggle(Unit *unit, uint16_t packed) return E_SUCCESS; } +error_t UU_DO_GetPinCount(Unit *unit, uint8_t *count) +{ + CHECK_TYPE(unit, &UNIT_DOUT); + struct priv *priv = unit->data; + + uint32_t packed = port_pack(0xFFFF, priv->pins); + *count = (uint8_t)(32 - __CLZ(packed)); + return E_SUCCESS; +} enum PinCmd_ { CMD_WRITE = 0, diff --git a/units/digital_out/unit_dout.h b/units/digital_out/unit_dout.h index 5eada10..0f7b3ef 100644 --- a/units/digital_out/unit_dout.h +++ b/units/digital_out/unit_dout.h @@ -9,4 +9,14 @@ extern const UnitDriver UNIT_DOUT; +error_t UU_DO_Write(Unit *unit, uint16_t packed); + +error_t UU_DO_Set(Unit *unit, uint16_t packed); + +error_t UU_DO_Clear(Unit *unit, uint16_t packed); + +error_t UU_DO_Toggle(Unit *unit, uint16_t packed); + +error_t UU_DO_GetPinCount(Unit *unit, uint8_t *count); + #endif //U_DOUT_H diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index c410c91..734dc6e 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -194,23 +194,23 @@ static error_t UI2C_init(Unit *unit) TRY(rsc_claim(unit, r_scl)); priv->port = port2periph(portname, &suc); - uint32_t ll_pin_scl = pin2ll(pin_scl, &suc); - uint32_t ll_pin_sda = pin2ll(pin_sda, &suc); + priv->ll_pin_scl = pin2ll(pin_scl, &suc); + priv->ll_pin_sda = pin2ll(pin_sda, &suc); if (!suc) return E_BAD_CONFIG; // configure AF - if (pin_scl < 8) LL_GPIO_SetAFPin_0_7(priv->port, ll_pin_scl, af_i2c); - else LL_GPIO_SetAFPin_8_15(priv->port, ll_pin_scl, af_i2c); + if (pin_scl < 8) LL_GPIO_SetAFPin_0_7(priv->port, priv->ll_pin_scl, af_i2c); + else LL_GPIO_SetAFPin_8_15(priv->port, priv->ll_pin_scl, af_i2c); - if (pin_sda < 8) LL_GPIO_SetAFPin_0_7(priv->port, ll_pin_sda, af_i2c); - else LL_GPIO_SetAFPin_8_15(priv->port, ll_pin_sda, af_i2c); + if (pin_sda < 8) LL_GPIO_SetAFPin_0_7(priv->port, priv->ll_pin_sda, af_i2c); + else LL_GPIO_SetAFPin_8_15(priv->port, priv->ll_pin_sda, af_i2c); - LL_GPIO_SetPinMode(priv->port, ll_pin_scl, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinMode(priv->port, ll_pin_sda, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinMode(priv->port, priv->ll_pin_scl, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinMode(priv->port, priv->ll_pin_sda, LL_GPIO_MODE_ALTERNATE); // set as OpenDrain (this may not be needed - TODO check) - LL_GPIO_SetPinOutputType(priv->port, ll_pin_scl, LL_GPIO_OUTPUT_OPENDRAIN); - LL_GPIO_SetPinOutputType(priv->port, ll_pin_sda, LL_GPIO_OUTPUT_OPENDRAIN); + LL_GPIO_SetPinOutputType(priv->port, priv->ll_pin_scl, LL_GPIO_OUTPUT_OPENDRAIN); + LL_GPIO_SetPinOutputType(priv->port, priv->ll_pin_sda, LL_GPIO_OUTPUT_OPENDRAIN); if (priv->periph_num == 1) { diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c new file mode 100644 index 0000000..a8b7773 --- /dev/null +++ b/units/spi/unit_spi.c @@ -0,0 +1,399 @@ +// +// Created by MightyPork on 2018/01/02. +// + +#include "comm/messages.h" +#include "unit_base.h" +#include "utils/avrlibc.h" +#include "unit_spi.h" + +// SPI master + +/** Private data structure */ +struct priv { + uint8_t periph_num; //!< 1 or 2 + uint16_t prescaller; //!< Clock prescaller, stored as the dividing factor + + bool cpol; //!< CPOL setting + bool cpha; //!< CPHA setting + bool tx_only; //!< If true, Enable only the MOSI line + bool lsb_first; //!< Option to send LSB first + + char ssn_port_name; //!< SSN port + uint16_t ssn_pins; //!< SSN pin mask + + SPI_TypeDef *periph; + + GPIO_TypeDef *ssn_port; + GPIO_TypeDef *spi_port; + uint32_t ll_pin_miso; + uint32_t ll_pin_mosi; + uint32_t ll_pin_sck; +}; + +// ------------------------------------------------------------------------ + +/** Load from a binary buffer stored in Flash */ +static void USPI_loadBinary(Unit *unit, PayloadParser *pp) +{ + struct priv *priv = unit->data; + + uint8_t version = pp_u8(pp); + (void)version; + + priv->periph_num = pp_u8(pp); + priv->prescaller = pp_u16(pp); + + priv->cpol = pp_bool(pp); + priv->cpha = pp_bool(pp); + priv->tx_only = pp_bool(pp); + priv->lsb_first = pp_bool(pp); + + priv->ssn_port_name = pp_char(pp); + priv->ssn_pins = pp_u16(pp); +} + +/** Write to a binary buffer for storing in Flash */ +static void USPI_writeBinary(Unit *unit, PayloadBuilder *pb) +{ + struct priv *priv = unit->data; + + pb_u8(pb, 0); // version + + pb_u8(pb, priv->periph_num); + pb_u16(pb, priv->prescaller); + + pb_bool(pb, priv->cpol); + pb_bool(pb, priv->cpha); + pb_bool(pb, priv->tx_only); + pb_bool(pb, priv->lsb_first); + + pb_char(pb, priv->ssn_port_name); + pb_u16(pb, priv->ssn_pins); +} + +// ------------------------------------------------------------------------ + +/** Parse a key-value pair from the INI file */ +static error_t USPI_loadIni(Unit *unit, const char *key, const char *value) +{ + bool suc = true; + struct priv *priv = unit->data; + + if (streq(key, "device")) { + priv->periph_num = (uint8_t) avr_atoi(value); + } + else if (streq(key, "prescaller")) { + priv->prescaller = (uint16_t ) avr_atoi(value); + } + else if (streq(key, "cpol")) { + priv->cpol = (bool) avr_atoi(value); + } + else if (streq(key, "cpha")) { + priv->cpha = (bool) avr_atoi(value); + } + else if (streq(key, "tx-only")) { + priv->tx_only = str_parse_yn(value, &suc); + } + else if (streq(key, "lsb-first")) { + priv->lsb_first = str_parse_yn(value, &suc); + } + else if (streq(key, "port")) { + suc = parse_port(value, &priv->ssn_port_name); + } + else if (streq(key, "pins")) { + priv->ssn_pins = parse_pinmask(value, &suc); + } + else { + return E_BAD_KEY; + } + + if (!suc) return E_BAD_VALUE; + return E_SUCCESS; +} + +/** Generate INI file section for the unit */ +static void USPI_writeIni(Unit *unit, IniWriter *iw) +{ + struct priv *priv = unit->data; + + iw_comment(iw, "Peripheral number (SPIx)"); + iw_entry(iw, "device", "%d", (int)priv->periph_num); + + iw_comment(iw, "Prescaller: 2,4,8,...,256"); + iw_entry(iw, "prescaller", "%d", (int)priv->prescaller); + + iw_comment(iw, "Clock polarity: 0,1 (clock idle level)"); + iw_entry(iw, "cpol", "%d", (int)priv->cpol); + + iw_comment(iw, "Clock phase: 0,1 (active edge, 0-first, 1-second)"); + iw_entry(iw, "cpha", "%d", (int)priv->cpha); + + iw_comment(iw, "Transmit only, disable MISO"); + iw_entry(iw, "tx-only", str_yn(priv->tx_only)); + + iw_comment(iw, "Use LSB-first bit order"); + iw_entry(iw, "lsb-first", str_yn(priv->lsb_first)); + + iw_comment(iw, "Slave Select port name"); + iw_entry(iw, "port", "%c", priv->ssn_port_name); + + iw_comment(iw, "Slave select pins (comma separated, supports ranges)"); + iw_entry(iw, "pins", "%s", str_pinmask(priv->ssn_pins, unit_tmp512)); +} + +// ------------------------------------------------------------------------ + +/** Allocate data structure and set defaults */ +static error_t USPI_preInit(Unit *unit) +{ + bool suc = true; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); + if (!suc) return E_OUT_OF_MEM; + + // some defaults + priv->periph_num = 1; + priv->prescaller = 64; + + priv->cpol = 0; + priv->cpha = 0; + priv->tx_only = false; + priv->lsb_first = false; + + priv->ssn_port_name = 'A'; + priv->ssn_pins = 0x0001; + + return E_SUCCESS; +} + +/** Finalize unit set-up */ +static error_t USPI_init(Unit *unit) +{ + bool suc = true; + struct priv *priv = unit->data; + + if (!(priv->periph_num >= 1 && priv->periph_num <= 2)) { + dbg("!! Bad SPI periph"); + // XXX some chips have also SPI3 + return E_BAD_CONFIG; + } + + + // assign and claim the peripheral + if (priv->periph_num == 1) { + TRY(rsc_claim(unit, R_SPI1)); + priv->periph = SPI1; + } + else if (priv->periph_num == 2) { + TRY(rsc_claim(unit, R_SPI2)); + priv->periph = SPI2; + } + + // This is written for F072, other platforms will need adjustments + + // Configure SPI own pins (AF) + + char spi_portname; + uint8_t pin_miso; + uint8_t pin_mosi; + uint8_t pin_sck; + uint32_t af_spi; + + // TODO +#if GEX_PLAT_F072_DISCOVERY + #error "NO IMPL" +#elif GEX_PLAT_F103_BLUEPILL + #error "NO IMPL" +#elif GEX_PLAT_F303_DISCOVERY + #error "NO IMPL" +#elif GEX_PLAT_F407_DISCOVERY + #error "NO IMPL" +#else + #error "BAD PLATFORM!" +#endif + + // first, we have to claim the pins + Resource r_mosi = pin2resource(spi_portname, pin_mosi, &suc); + Resource r_miso = pin2resource(spi_portname, pin_miso, &suc); + Resource r_sck = pin2resource(spi_portname, pin_sck, &suc); + if (!suc) return E_BAD_CONFIG; + + TRY(rsc_claim(unit, r_mosi)); + TRY(rsc_claim(unit, r_miso)); + TRY(rsc_claim(unit, r_sck)); + + priv->spi_port = port2periph(spi_portname, &suc); + priv->ll_pin_mosi = pin2ll(pin_mosi, &suc); + priv->ll_pin_miso = pin2ll(pin_miso, &suc); + priv->ll_pin_sck = pin2ll(pin_sck, &suc); + if (!suc) return E_BAD_CONFIG; + + // configure AF + if (pin_mosi < 8) LL_GPIO_SetAFPin_0_7(priv->spi_port, priv->ll_pin_mosi, af_spi); + else LL_GPIO_SetAFPin_8_15(priv->spi_port, priv->ll_pin_mosi, af_spi); + + if (pin_miso < 8) LL_GPIO_SetAFPin_0_7(priv->spi_port, priv->ll_pin_miso, af_spi); + else LL_GPIO_SetAFPin_8_15(priv->spi_port, priv->ll_pin_miso, af_spi); + + if (pin_sck < 8) LL_GPIO_SetAFPin_0_7(priv->spi_port, priv->ll_pin_sck, af_spi); + else LL_GPIO_SetAFPin_8_15(priv->spi_port, priv->ll_pin_sck, af_spi); + + LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_mosi, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_miso, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_sck, LL_GPIO_MODE_ALTERNATE); + + if (priv->periph_num == 1) { + __HAL_RCC_SPI1_CLK_ENABLE(); + } else { + __HAL_RCC_SPI2_CLK_ENABLE(); + } + + // configure SSN GPIOs + { + priv->ssn_port = port2periph(priv->ssn_port_name, &suc); + if (!suc) return E_BAD_CONFIG; + + // Claim all needed pins + TRY(rsc_claim_gpios(unit, priv->ssn_port_name, priv->ssn_pins)); + + uint16_t mask = 1; + for (int i = 0; i < 16; i++, mask <<= 1) { + if (priv->ssn_pins & mask) { + uint32_t ll_pin = pin2ll((uint8_t) i, &suc); + LL_GPIO_SetPinMode(priv->ssn_port, ll_pin, LL_GPIO_MODE_OUTPUT); + LL_GPIO_SetPinOutputType(priv->ssn_port, ll_pin, LL_GPIO_OUTPUT_PUSHPULL); + LL_GPIO_SetPinSpeed(priv->ssn_port, ll_pin, LL_GPIO_SPEED_FREQ_HIGH); + } + } + + // Set the initial state - all high + priv->ssn_port->ODR &= priv->ssn_pins; + } + + // Configure SPI - must be configured under reset + LL_SPI_Disable(priv->periph); + { + uint32_t presc = priv->prescaller; + uint32_t lz = __CLZ(presc); + if (lz < 23) lz = 23; + if (lz > 30) lz = 30; + presc = (32 - lz - 2); + dbg("Presc is %d", (int) presc); + LL_SPI_SetBaudRatePrescaler(priv->periph, presc); + + LL_SPI_SetClockPolarity(priv->periph, priv->cpol ? + LL_SPI_POLARITY_HIGH : + LL_SPI_POLARITY_LOW); + + LL_SPI_SetClockPhase(priv->periph, priv->cpha ? + LL_SPI_PHASE_1EDGE : + LL_SPI_PHASE_2EDGE); + + LL_SPI_SetTransferDirection(priv->periph, priv->tx_only ? + LL_SPI_HALF_DUPLEX_TX : + LL_SPI_FULL_DUPLEX); + + LL_SPI_SetTransferBitOrder(priv->periph, priv->lsb_first ? + LL_SPI_LSB_FIRST : + LL_SPI_MSB_FIRST); + + // TODO data size? + + LL_SPI_SetMode(priv->periph, LL_SPI_MODE_MASTER); + } + LL_SPI_Enable(priv->periph); + + return E_SUCCESS; +} + +/** Tear down the unit */ +static void USPI_deInit(Unit *unit) +{ + struct priv *priv = unit->data; + + // de-init the pins & peripheral only if inited correctly + if (unit->status == E_SUCCESS) { + assert_param(priv->periph); + assert_param(priv->spi_port); + assert_param(priv->ssn_port); + + LL_SPI_DeInit(priv->periph); + + if (priv->periph_num == 1) { + __HAL_RCC_SPI1_CLK_DISABLE(); + } else { + __HAL_RCC_SPI2_CLK_DISABLE(); + } + + LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_mosi, LL_GPIO_MODE_ANALOG); + LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_mosi, LL_GPIO_MODE_ANALOG); + LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_sck, LL_GPIO_MODE_ANALOG); + + // de-init all SSN pins + bool suc = true; + uint16_t mask = 1; + for (int i = 0; i < 16; i++, mask <<= 1) { + if (priv->ssn_pins & mask) { + uint32_t ll_pin = pin2ll((uint8_t) i, &suc); + assert_param(suc); + // configure the pin as analog + LL_GPIO_SetPinMode(priv->ssn_port, ll_pin, LL_GPIO_MODE_ANALOG); + } + } + } + + // Release all resources + rsc_teardown(unit); + + // Free memory + free(unit->data); + unit->data = NULL; +} + +// ------------------------------------------------------------------------ + +enum PinCmd_ { + CMD_WRITE = 0, +}; + +/** Handle a request message */ +static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +{ + uint16_t addr; + uint32_t len; + uint8_t regnum; + uint32_t size; + + // NOTE: 10-bit addresses must have the highest bit set to 1 for indication (0x8000 | addr) + + switch (command) { + /** Write byte(s) - addr:u16, byte(s) */ + case CMD_WRITE: + addr = pp_u16(pp); + const uint8_t *bb = pp_tail(pp, &len); + + return UU_SPI_Write(unit, addr, bb, len); // TODo implement function + SPI pins mapping + + default: + return E_UNKNOWN_COMMAND; + } +} + +// ------------------------------------------------------------------------ + +/** Unit template */ +const UnitDriver UNIT_SPI = { + .name = "SPI", + .description = "SPI master", + // Settings + .preInit = USPI_preInit, + .cfgLoadBinary = USPI_loadBinary, + .cfgWriteBinary = USPI_writeBinary, + .cfgLoadIni = USPI_loadIni, + .cfgWriteIni = USPI_writeIni, + // Init + .init = USPI_init, + .deInit = USPI_deInit, + // Function + .handleRequest = USPI_handleRequest, +}; diff --git a/units/spi/unit_spi.h b/units/spi/unit_spi.h new file mode 100644 index 0000000..0374459 --- /dev/null +++ b/units/spi/unit_spi.h @@ -0,0 +1,48 @@ +// +// Created by MightyPork on 2018/01/02. +// + +#ifndef GEX_F072_UNIT_SPI_H +#define GEX_F072_UNIT_SPI_H + +#include "unit.h" + +extern const UnitDriver UNIT_SPI; + +// Unit-to-Unit API + +/** + * Raw read/write via SPI. + * It's possible to simultaneously write and read, or skip bytes in either direction. + * + * Example scenarios: + * + * req 2, skip 2, read 3 + * |<-- req_len --->| + * [ write ][ write ] . . . . . . . . + * . . . . . . . . . [ read ][ read ][ read ] + * |<-- resp_skip ->|<------ resp_len ----->| + * + * req 2, skip 0, read 2 + * |<-- req_len --->| + * [ write ][ write ] + * [ read ][ read ] + * |<-- resp_len -->| + * + * @param unit - SPI unit + * @param slave_num - slave number (SS pin index) + * @param request - request bytes buffer + * @param response - response bytes buffer + * @param req_len - number of bytes in the request. Will be right-padded with zeros. + * @param resp_skip - response bytes to discard before starting to capture them + * @param resp_len - number of bytes to capture, after discarding resp_skip received bytes + * @return success + */ +error_t UU_SPI_Write(Unit *unit, uint8_t slave_num, + const uint8_t *request, + uint8_t *response, + uint32_t req_len, + uint32_t resp_skip, + uint32_t resp_len); + +#endif //GEX_F072_UNIT_SPI_H From 0f75690310a584c414a08351917b8ebc4151bba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 5 Jan 2018 09:59:27 +0100 Subject: [PATCH 02/13] added SPI pin mappings for f072 --- units/spi/unit_spi.c | 71 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index a8b7773..043a6f0 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -12,13 +12,14 @@ /** Private data structure */ struct priv { uint8_t periph_num; //!< 1 or 2 - uint16_t prescaller; //!< Clock prescaller, stored as the dividing factor + uint8_t remap; //!< SPI remap option + uint16_t prescaller; //!< Clock prescaller, stored as the dividing factor bool cpol; //!< CPOL setting bool cpha; //!< CPHA setting bool tx_only; //!< If true, Enable only the MOSI line - bool lsb_first; //!< Option to send LSB first + bool lsb_first; //!< Option to send LSB first char ssn_port_name; //!< SSN port uint16_t ssn_pins; //!< SSN pin mask @@ -43,6 +44,7 @@ static void USPI_loadBinary(Unit *unit, PayloadParser *pp) priv->periph_num = pp_u8(pp); priv->prescaller = pp_u16(pp); + priv->remap = pp_u8(pp); priv->cpol = pp_bool(pp); priv->cpha = pp_bool(pp); @@ -62,6 +64,7 @@ static void USPI_writeBinary(Unit *unit, PayloadBuilder *pb) pb_u8(pb, priv->periph_num); pb_u16(pb, priv->prescaller); + pb_u8(pb, priv->remap); pb_bool(pb, priv->cpol); pb_bool(pb, priv->cpha); @@ -83,6 +86,9 @@ static error_t USPI_loadIni(Unit *unit, const char *key, const char *value) if (streq(key, "device")) { priv->periph_num = (uint8_t) avr_atoi(value); } + if (streq(key, "remap")) { + priv->remap = (uint8_t) avr_atoi(value); + } else if (streq(key, "prescaller")) { priv->prescaller = (uint16_t ) avr_atoi(value); } @@ -117,9 +123,14 @@ static void USPI_writeIni(Unit *unit, IniWriter *iw) { struct priv *priv = unit->data; + // TODO show a legend for peripherals and remaps + iw_comment(iw, "Peripheral number (SPIx)"); iw_entry(iw, "device", "%d", (int)priv->periph_num); + iw_comment(iw, "SPI port remap (0,1,...)"); + iw_entry(iw, "remap", "%d", (int)priv->remap); + iw_comment(iw, "Prescaller: 2,4,8,...,256"); iw_entry(iw, "prescaller", "%d", (int)priv->prescaller); @@ -154,6 +165,7 @@ static error_t USPI_preInit(Unit *unit) // some defaults priv->periph_num = 1; priv->prescaller = 64; + priv->remap = 0; priv->cpol = 0; priv->cpha = 0; @@ -201,7 +213,60 @@ static error_t USPI_init(Unit *unit) // TODO #if GEX_PLAT_F072_DISCOVERY - #error "NO IMPL" + + // SPI1 - many options + // sck, miso, mosi, af + + if (priv->periph_num == 1) { + // SPI1 + if (priv->remap == 0) { + spi_portname = 'A'; + af_spi = LL_GPIO_AF_0; + pin_sck = 5; + pin_miso = 6; + pin_mosi = 7; + } + else if (priv->remap == 1) { + spi_portname = 'B'; + af_spi = LL_GPIO_AF_0; + pin_sck = 3; + pin_miso = 4; + pin_mosi = 5; + } + else if (priv->remap == 2) { + // large packages only + spi_portname = 'E'; + af_spi = LL_GPIO_AF_1; + pin_sck = 13; + pin_miso = 14; + pin_mosi = 15; + } + else { + return E_BAD_CONFIG; + } + } + else { + // SPI2 + if (priv->remap == 0) { + spi_portname = 'B'; + af_spi = LL_GPIO_AF_0; + pin_sck = 13; + pin_miso = 14; + pin_mosi = 15; + } + else if (priv->remap == 1) { + // NOTE: the's also a incomplete remap in PB and PC + spi_portname = 'D'; + af_spi = LL_GPIO_AF_0; + pin_sck = 1; + pin_miso = 3; + pin_mosi = 4; + } + else { + return E_BAD_CONFIG; + } + } + #elif GEX_PLAT_F103_BLUEPILL #error "NO IMPL" #elif GEX_PLAT_F303_DISCOVERY From 913f431a54cbeb56bf7027b8e84974c89b084e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 5 Jan 2018 10:11:57 +0100 Subject: [PATCH 03/13] stub of SPI write cmd, multicast cmd --- gex.mk | 1 + platform/platform.c | 2 ++ units/spi/unit_spi.c | 63 +++++++++++++++++++++++++++++++++++++------- units/spi/unit_spi.h | 17 +++++++++++- utils/error.h | 1 + 5 files changed, 74 insertions(+), 10 deletions(-) diff --git a/gex.mk b/gex.mk index 7de5234..8eb9e9a 100644 --- a/gex.mk +++ b/gex.mk @@ -11,6 +11,7 @@ GEX_SRC_DIR = \ User/units/digital_out \ User/units/digital_in \ User/units/i2c \ + User/units/spi \ User/TinyFrame \ User/CWPack \ User/tasks diff --git a/platform/platform.c b/platform/platform.c index 95ca54f..bfd439f 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -13,6 +13,7 @@ #include "units/neopixel/unit_neopixel.h" #include "units/i2c/unit_i2c.h" #include "units/test/unit_test.h" +#include "units/spi/unit_spi.h" void plat_init_resources(void) { @@ -77,6 +78,7 @@ void plat_init_resources(void) ureg_add_type(&UNIT_DIN); ureg_add_type(&UNIT_NEOPIXEL); ureg_add_type(&UNIT_I2C); + ureg_add_type(&UNIT_SPI); // Free all present resources { diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index 043a6f0..df893b8 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -417,27 +417,72 @@ static void USPI_deInit(Unit *unit) // ------------------------------------------------------------------------ + +error_t UU_SPI_Multicast(Unit *unit, uint16_t slaves, + const uint8_t *request, + uint32_t req_len) +{ + // + + return E_NOT_IMPLEMENTED; +} + +error_t UU_SPI_Write(Unit *unit, uint8_t slave_num, + const uint8_t *request, + uint8_t *response, + uint32_t req_len, + uint32_t resp_skip, + uint32_t resp_len) +{ + // + + return E_NOT_IMPLEMENTED; +} + + enum PinCmd_ { CMD_WRITE = 0, + CMD_MULTICAST = 1, }; /** Handle a request message */ static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { - uint16_t addr; - uint32_t len; - uint8_t regnum; - uint32_t size; + uint8_t slave; + uint16_t slaves; + uint16_t req_len; + uint16_t resp_skip; + uint16_t resp_len; + const uint8_t *bb; - // NOTE: 10-bit addresses must have the highest bit set to 1 for indication (0x8000 | addr) + uint32_t len; switch (command) { - /** Write byte(s) - addr:u16, byte(s) */ + /** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */ case CMD_WRITE: - addr = pp_u16(pp); - const uint8_t *bb = pp_tail(pp, &len); + slave = pp_u8(pp); + req_len = pp_u16(pp); + resp_skip = pp_u16(pp); + resp_len = pp_u16(pp); + + bb = pp_tail(pp, &len); + + TRY(UU_SPI_Write(unit, slave, + bb, (uint8_t *) unit_tmp512, + req_len, resp_skip, resp_len)); + + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, resp_len); + return E_SUCCESS; + + /** Write byte(s) to multiple slaves - slaves:u16, req_len:u16, byte(s) */ + case CMD_MULTICAST: + slaves = pp_u16(pp); + req_len = pp_u16(pp); + + bb = pp_tail(pp, &len); - return UU_SPI_Write(unit, addr, bb, len); // TODo implement function + SPI pins mapping + TRY(UU_SPI_Multicast(unit, slaves, bb, req_len)); + return E_SUCCESS; default: return E_UNKNOWN_COMMAND; diff --git a/units/spi/unit_spi.h b/units/spi/unit_spi.h index 0374459..bfa3742 100644 --- a/units/spi/unit_spi.h +++ b/units/spi/unit_spi.h @@ -30,7 +30,7 @@ extern const UnitDriver UNIT_SPI; * |<-- resp_len -->| * * @param unit - SPI unit - * @param slave_num - slave number (SS pin index) + * @param slave_num - slave number (SS pin index, counted from least significant bit) * @param request - request bytes buffer * @param response - response bytes buffer * @param req_len - number of bytes in the request. Will be right-padded with zeros. @@ -45,4 +45,19 @@ error_t UU_SPI_Write(Unit *unit, uint8_t slave_num, uint32_t resp_skip, uint32_t resp_len); +/** + * Write to multiple slaves at once. + * This is similar to UU_SPI_Write, but performs no read and works only if the device + * is configured as tx-only. + * + * @param unit - SPI unit + * @param slaves - bitmap of slaves to write (packed bits representing the SSN pins) + * @param request - request bytes buffer + * @param req_len - length of the request buffer + * @return success + */ +error_t UU_SPI_Multicast(Unit *unit, uint16_t slaves, + const uint8_t *request, + uint32_t req_len); + #endif //GEX_F072_UNIT_SPI_H diff --git a/utils/error.h b/utils/error.h index 2e9cc99..9b52727 100644 --- a/utils/error.h +++ b/utils/error.h @@ -42,6 +42,7 @@ X(OVERRUN, NULL) /* used in bulk transfer */ \ X(PROTOCOL_BREACH, NULL) /* eating with the wrong spoon */ \ X(BAD_UNIT_TYPE, NULL) \ + X(NOT_IMPLEMENTED, NULL) \ \ /* VFS user errors (those are meant to be shown to user) */ \ X(ERROR_DURING_TRANSFER, "Error during transfer") \ From 931f6cea5999e22352236121d49e48d97930a91f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 15:53:56 +0100 Subject: [PATCH 04/13] added missing mutex for shared scratch buffer --- comm/msg_bulkread.c | 6 ++-- framework/settings.c | 8 ++++- framework/unit.c | 2 +- framework/unit.h | 2 +- framework/unit_registry.c | 63 +++++++++++++++++++++---------------- freertos.c | 6 ++++ platform/plat_compat.h | 5 +-- tasks/task_msg.c | 3 +- units/digital_in/unit_din.c | 2 +- units/i2c/unit_i2c.c | 2 +- 10 files changed, 61 insertions(+), 38 deletions(-) diff --git a/comm/msg_bulkread.c b/comm/msg_bulkread.c index 1151b23..0bc31f8 100644 --- a/comm/msg_bulkread.c +++ b/comm/msg_bulkread.c @@ -11,7 +11,7 @@ #include "utils/payload_builder.h" /** Buffer for preparing bulk chunks */ -static uint8_t bulkread_buffer[BULKREAD_MAX_CHUNK]; +static uint8_t bulkread_buffer[BULK_READ_BUF_LEN]; /** * TF listener for the bulk read transaction @@ -36,7 +36,7 @@ static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) uint32_t chunk = pp_u32(&pp); chunk = MIN(chunk, bulk->len - bulk->offset); - chunk = MIN(chunk, BULKREAD_MAX_CHUNK); + chunk = MIN(chunk, BULK_READ_BUF_LEN); // load data into the buffer bulk->read(bulk, chunk, bulkread_buffer); @@ -81,7 +81,7 @@ void bulkread_start(TinyFrame *tf, BulkRead *bulk) uint8_t buf[8]; PayloadBuilder pb = pb_start(buf, 4, NULL); pb_u32(&pb, bulk->len); - pb_u32(&pb, BULKREAD_MAX_CHUNK); + pb_u32(&pb, BULK_READ_BUF_LEN); // We use userdata1 to hold a reference to the bulk transfer TF_Msg msg = { diff --git a/framework/settings.c b/framework/settings.c index 42277bd..073366b 100644 --- a/framework/settings.c +++ b/framework/settings.c @@ -223,6 +223,8 @@ static void ini_preamble(IniWriter *iw, const char *filename) iw_comment(iw, "Close the LOCK jumper to save them to Flash."); } +extern osMutexId mutScratchBufferHandle; + /** * Write system settings to INI (without section) */ @@ -230,7 +232,11 @@ void settings_build_units_ini(IniWriter *iw) { ini_preamble(iw, "UNITS.INI"); - ureg_build_ini(iw); + assert_param(osOK == osMutexWait(mutScratchBufferHandle, 5000)); + { + ureg_build_ini(iw); + } + assert_param(osOK == osMutexRelease(mutScratchBufferHandle)); } /** diff --git a/framework/unit.c b/framework/unit.c index 872b596..a1839f4 100644 --- a/framework/unit.c +++ b/framework/unit.c @@ -6,7 +6,7 @@ #include "unit.h" #include "resources.h" -char unit_tmp512[512]; +char unit_tmp512[UNIT_TMP_LEN]; // Abort partly inited unit void clean_failed_unit(Unit *unit) diff --git a/framework/unit.h b/framework/unit.h index 0cb86fa..9f85696 100644 --- a/framework/unit.h +++ b/framework/unit.h @@ -16,7 +16,7 @@ return E_BAD_UNIT_TYPE; \ } while (0) -extern char unit_tmp512[512]; // temporary static buffer - not expected to be accessed asynchronously +extern char unit_tmp512[UNIT_TMP_LEN]; // temporary static buffer - not expected to be accessed asynchronously // TODO add mutex? typedef struct unit Unit; diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 7af2d51..575bbaa 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -431,42 +431,51 @@ uint32_t ureg_get_num_units(void) return (uint32_t) unit_count; } +extern osMutexId mutScratchBufferHandle; + /** Deliver message to it's destination unit */ void ureg_deliver_unit_request(TF_Msg *msg) { - PayloadParser pp = pp_start(msg->data, msg->len, NULL); - uint8_t callsign = pp_u8(&pp); - uint8_t command = pp_u8(&pp); + // we must claim the scratch buffer because it's used by many units internally + assert_param(osOK == osMutexWait(mutScratchBufferHandle, 5000)); + { + PayloadParser pp = pp_start(msg->data, msg->len, NULL); + uint8_t callsign = pp_u8(&pp); + uint8_t command = pp_u8(&pp); - // highest bit indicates user wants an extra confirmation on success - bool confirmed = (bool) (command & 0x80); - command &= 0x7F; + // highest bit indicates user wants an extra confirmation on success + bool confirmed = (bool) (command & 0x80); + command &= 0x7F; - if (callsign == 0 || !pp.ok) { - com_respond_error(msg->frame_id, E_MALFORMED_COMMAND); - return; - } + if (callsign == 0 || !pp.ok) { + com_respond_error(msg->frame_id, E_MALFORMED_COMMAND); + goto quit; + } - UlistEntry *li = ulist_head; - while (li != NULL) { - Unit *const pUnit = &li->unit; - if (pUnit->callsign == callsign && pUnit->status == E_SUCCESS) { - error_t rv = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); - - // send extra SUCCESS confirmation message. - // error is expected to have already been reported. - if (rv == E_SUCCESS) { - if (confirmed) com_respond_ok(msg->frame_id); - } else { - com_respond_error(msg->frame_id, rv); + UlistEntry *li = ulist_head; + while (li != NULL) { + Unit *const pUnit = &li->unit; + if (pUnit->callsign == callsign && pUnit->status == E_SUCCESS) { + error_t rv = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); + + // send extra SUCCESS confirmation message. + // error is expected to have already been reported. + if (rv == E_SUCCESS) { + if (confirmed) com_respond_ok(msg->frame_id); + } + else { + com_respond_error(msg->frame_id, rv); + } + goto quit; } - return; + li = li->next; } - li = li->next; - } - // Not found - com_respond_error(msg->frame_id, E_NO_SUCH_UNIT); + // Not found + com_respond_error(msg->frame_id, E_NO_SUCH_UNIT); + } + quit: + assert_param(osOK == osMutexRelease(mutScratchBufferHandle)); } /** Send a response for a unit-list request */ diff --git a/freertos.c b/freertos.c index 4d1e643..1de37d0 100644 --- a/freertos.c +++ b/freertos.c @@ -84,6 +84,9 @@ osStaticMutexDef_t mutTinyFrameTxControlBlock; osSemaphoreId semVcomTxReadyHandle; osStaticSemaphoreDef_t semVcomTxReadyControlBlock; +osMutexId mutScratchBufferHandle; +osStaticMutexDef_t mutScratchBufferControlBlock; + /* USER CODE BEGIN Variables */ /* USER CODE END Variables */ @@ -142,6 +145,9 @@ void MX_FREERTOS_Init(void) { osMutexStaticDef(mutTinyFrameTx, &mutTinyFrameTxControlBlock); mutTinyFrameTxHandle = osMutexCreate(osMutex(mutTinyFrameTx)); + osMutexStaticDef(mutScratchBuffer, &mutScratchBufferControlBlock); + mutScratchBufferHandle = osMutexCreate(osMutex(mutScratchBuffer)); + /* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */ diff --git a/platform/plat_compat.h b/platform/plat_compat.h index 0b46caa..c8e0627 100644 --- a/platform/plat_compat.h +++ b/platform/plat_compat.h @@ -9,10 +9,11 @@ // -------- Static buffers --------- #define TSK_STACK_MAIN 220 // USB / VFS task stack size -#define TSK_STACK_MSG 200 // TF message handler task stack size +#define TSK_STACK_MSG 220 // TF message handler task stack size #define TSK_STACK_JOBRUNNER 80 // Job runner task stack size -#define BULKREAD_MAX_CHUNK 256 // Bulk read buffer +#define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads +#define UNIT_TMP_LEN 512 // Buffer for bulk read and varions internal unit operations #define FLASH_SAVE_BUF_LEN 256 // Static buffer for saving to flash diff --git a/tasks/task_msg.c b/tasks/task_msg.c index 88d1fb4..f1fcc2d 100644 --- a/tasks/task_msg.c +++ b/tasks/task_msg.c @@ -26,6 +26,7 @@ void TaskMessaging(const void * argument) xQueueReceive(queRxDataHandle, &slot, osWaitForever); assert_param(slot.len>0 && slot.len<=64); // check the len is within bounds + // We need thr scratch buffer for many unit command handlers TF_Accept(comm, slot.data, slot.len); #if USE_STACK_MONITOR @@ -34,4 +35,4 @@ void TaskMessaging(const void * argument) msgQueHighWaterMark = MAX(msgQueHighWaterMark, count); #endif } -} \ No newline at end of file +} diff --git a/units/digital_in/unit_din.c b/units/digital_in/unit_din.c index f55247e..01c321b 100644 --- a/units/digital_in/unit_din.c +++ b/units/digital_in/unit_din.c @@ -210,7 +210,7 @@ static error_t DI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay case CMD_READ:; TRY(UU_DI_Read(unit, &packed)); - PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 64, NULL); + PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, UNIT_TMP_LEN, NULL); pb_u16(&pb, packed); com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, pb_length(&pb)); return E_SUCCESS; diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index 734dc6e..796691a 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -380,7 +380,7 @@ error_t UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t CHECK_TYPE(unit, &UNIT_I2C); // we have to insert the address first - needs a buffer (XXX realistically the buffer needs 1-4 bytes + addr) - PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 512, NULL); + PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, UNIT_TMP_LEN, NULL); pb_u8(&pb, regnum); pb_buf(&pb, bytes, width); From e82306c36f338ae2284919c186b84f58f93347d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 16:09:54 +0100 Subject: [PATCH 05/13] added more informative error message to unit failed due to rsc not avail --- framework/resources.c | 21 ++++++++++- framework/resources.h | 75 +++----------------------------------- framework/rsc_enum.h | 77 +++++++++++++++++++++++++++++++++++++++ framework/unit.h | 8 +++- framework/unit_registry.c | 9 ++++- 5 files changed, 117 insertions(+), 73 deletions(-) create mode 100644 framework/rsc_enum.h diff --git a/framework/resources.c b/framework/resources.c index e901e81..6e7b9b6 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -24,6 +24,21 @@ const char *const rsc_names[] = { #undef X }; +/** Get rsc name */ +const char * rsc_get_name(Resource rsc) +{ + assert_param(rsc < R_RESOURCE_COUNT); + return rsc_names[rsc]; +} + +/** Get rsc owner name */ +const char * rsc_get_owner_name(Resource rsc) +{ + assert_param(rsc < R_RESOURCE_COUNT); + if (resources[rsc].owner == NULL) return "NULL"; + return resources[rsc].owner->name; +} + /** * Initialize the resources registry */ @@ -51,7 +66,11 @@ error_t rsc_claim(Unit *unit, Resource rsc) if (resources[rsc].owner) { //TODO properly report to user dbg("ERROR!! Unit %s failed to claim resource %s, already held by %s!", - unit->name, rsc_names[rsc], resources[rsc].owner->name); + unit->name, + rsc_get_name(rsc), + rsc_get_owner_name(rsc)); + + unit->failed_rsc = rsc; return E_RESOURCE_NOT_AVAILABLE; } diff --git a/framework/resources.h b/framework/resources.h index e9f6254..8290cf4 100644 --- a/framework/resources.h +++ b/framework/resources.h @@ -7,78 +7,10 @@ #include "platform.h" #include "unit.h" +#include "rsc_enum.h" #define CHECK_SUC() do { if (!suc) return false; } while (0) -// X macro: Resource name, -#define XX_RESOURCES \ - X(NONE) \ - X(PA0) X(PA1) X(PA2) X(PA3) X(PA4) X(PA5) X(PA6) X(PA7) \ - X(PA8) X(PA9) X(PA10) X(PA11) X(PA12) X(PA13) X(PA14) X(PA15) \ - X(PB0) X(PB1) X(PB2) X(PB3) X(PB4) X(PB5) X(PB6) X(PB7) \ - X(PB8) X(PB9) X(PB10) X(PB11) X(PB12) X(PB13) X(PB14) X(PB15) \ - X(PC0) X(PC1) X(PC2) X(PC3) X(PC4) X(PC5) X(PC6) X(PC7) \ - X(PC8) X(PC9) X(PC10) X(PC11) X(PC12) X(PC13) X(PC14) X(PC15) \ - X(PD0) X(PD1) X(PD2) X(PD3) X(PD4) X(PD5) X(PD6) X(PD7) \ - X(PD8) X(PD9) X(PD10) X(PD11) X(PD12) X(PD13) X(PD14) X(PD15) \ - X(PE0) X(PE1) X(PE2) X(PE3) X(PE4) X(PE5) X(PE6) X(PE7) \ - X(PE8) X(PE9) X(PE10) X(PE11) X(PE12) X(PE13) X(PE14) X(PE15) \ - X(PF0) X(PF1) X(PF2) X(PF3) X(PF4) X(PF5) X(PF6) X(PF7) \ - X(PF8) X(PF9) X(PF10) X(PF11) X(PF12) X(PF13) X(PF14) X(PF15) \ - X(SPI1) X(SPI2) X(SPI3) \ - X(I2C1) X(I2C2) X(I2C3) \ - X(I2S1) X(I2S2) X(I2S3) \ - X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ - X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) \ - X(DAC1) X(DAC2) \ - X(CAN1) X(CAN2) \ - X(TSC) \ - X(DCMI) \ - X(ETH) \ - X(FSMC) \ - X(SDIO) \ - X(COMP1) X(COMP2) X(COMP3) X(COMP4) X(COMP5) X(COMP6) X(COMP7) \ - X(HDMI_CEC) \ - X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ - X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ - X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \ - X(TIM15) X(TIM16) X(TIM17) \ - X(DMA1) X(DMA2) \ - X(RNG) X(LCD) - -// GPIOs are allocated whenever the pin is needed -// (e.g. when used for SPI, the R_SPI resource as well as the corresponding R_GPIO resources must be claimed) - -// Peripheral blocks (IPs) - not all chips have all blocks, usually the 1 and 2 are present as a minimum, if any. -// It doesn't really make sense to expose multiple instances of buses that support addressing - -// ADCs - some more advanced chips support differential input mode on some (not all!) inputs -// Usually only one or two instances are present - -// DAC - often only one is present, or none. - -// UARTs -// - 1 and 2 are present universally, 2 is connected to VCOM on Nucleo/Discovery boards, good for debug messages -// 4 and 5 don't support synchronous mode. - -// Timers -// - some support quadrature input, probably all support external clock / gating / clock-out/PWM generation -// Not all chips have all timers and not all timers are equal. - -// DMA - Direct memory access lines - TODO split those to channels, they can be used separately - -// The resource registry will be pre-loaded with platform-specific config of which blocks are available - the rest will be "pre-claimed" -// (i.e. unavailable to functional modules) - -typedef enum hw_resource Resource; - -enum hw_resource { -#define X(res_name) R_##res_name, - XX_RESOURCES -#undef X - R_RESOURCE_COUNT -}; - void rsc_init_registry(void); error_t rsc_claim(Unit *unit, Resource rsc); @@ -98,4 +30,9 @@ void rsc_teardown(Unit *unit); void rsc_free(Unit *unit, Resource rsc); void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1); +const char * rsc_get_name(Resource rsc); + +/** Get rsc owner name */ +const char * rsc_get_owner_name(Resource rsc); + #endif //GEX_RESOURCES_H diff --git a/framework/rsc_enum.h b/framework/rsc_enum.h new file mode 100644 index 0000000..408e531 --- /dev/null +++ b/framework/rsc_enum.h @@ -0,0 +1,77 @@ +// +// Created by MightyPork on 2018/01/06. +// + +#ifndef GEX_F072_RSC_ENUM_H +#define GEX_F072_RSC_ENUM_H + +// X macro: Resource name, +#define XX_RESOURCES \ + X(NONE) \ + X(PA0) X(PA1) X(PA2) X(PA3) X(PA4) X(PA5) X(PA6) X(PA7) \ + X(PA8) X(PA9) X(PA10) X(PA11) X(PA12) X(PA13) X(PA14) X(PA15) \ + X(PB0) X(PB1) X(PB2) X(PB3) X(PB4) X(PB5) X(PB6) X(PB7) \ + X(PB8) X(PB9) X(PB10) X(PB11) X(PB12) X(PB13) X(PB14) X(PB15) \ + X(PC0) X(PC1) X(PC2) X(PC3) X(PC4) X(PC5) X(PC6) X(PC7) \ + X(PC8) X(PC9) X(PC10) X(PC11) X(PC12) X(PC13) X(PC14) X(PC15) \ + X(PD0) X(PD1) X(PD2) X(PD3) X(PD4) X(PD5) X(PD6) X(PD7) \ + X(PD8) X(PD9) X(PD10) X(PD11) X(PD12) X(PD13) X(PD14) X(PD15) \ + X(PE0) X(PE1) X(PE2) X(PE3) X(PE4) X(PE5) X(PE6) X(PE7) \ + X(PE8) X(PE9) X(PE10) X(PE11) X(PE12) X(PE13) X(PE14) X(PE15) \ + X(PF0) X(PF1) X(PF2) X(PF3) X(PF4) X(PF5) X(PF6) X(PF7) \ + X(PF8) X(PF9) X(PF10) X(PF11) X(PF12) X(PF13) X(PF14) X(PF15) \ + X(SPI1) X(SPI2) X(SPI3) \ + X(I2C1) X(I2C2) X(I2C3) \ + X(I2S1) X(I2S2) X(I2S3) \ + X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ + X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) \ + X(DAC1) X(DAC2) \ + X(CAN1) X(CAN2) \ + X(TSC) \ + X(DCMI) \ + X(ETH) \ + X(FSMC) \ + X(SDIO) \ + X(COMP1) X(COMP2) X(COMP3) X(COMP4) X(COMP5) X(COMP6) X(COMP7) \ + X(HDMI_CEC) \ + X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ + X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ + X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \ + X(TIM15) X(TIM16) X(TIM17) \ + X(DMA1) X(DMA2) \ + X(RNG) X(LCD) + +// GPIOs are allocated whenever the pin is needed +// (e.g. when used for SPI, the R_SPI resource as well as the corresponding R_GPIO resources must be claimed) + +// Peripheral blocks (IPs) - not all chips have all blocks, usually the 1 and 2 are present as a minimum, if any. +// It doesn't really make sense to expose multiple instances of buses that support addressing + +// ADCs - some more advanced chips support differential input mode on some (not all!) inputs +// Usually only one or two instances are present + +// DAC - often only one is present, or none. + +// UARTs +// - 1 and 2 are present universally, 2 is connected to VCOM on Nucleo/Discovery boards, good for debug messages +// 4 and 5 don't support synchronous mode. + +// Timers +// - some support quadrature input, probably all support external clock / gating / clock-out/PWM generation +// Not all chips have all timers and not all timers are equal. + +// DMA - Direct memory access lines - TODO split those to channels, they can be used separately + +// The resource registry will be pre-loaded with platform-specific config of which blocks are available - the rest will be "pre-claimed" +// (i.e. unavailable to functional modules) + +typedef enum hw_resource Resource; + +enum hw_resource { +#define X(res_name) R_##res_name, + XX_RESOURCES +#undef X + R_RESOURCE_COUNT +}; + +#endif //GEX_F072_RSC_ENUM_H diff --git a/framework/unit.h b/framework/unit.h index 9f85696..604cdee 100644 --- a/framework/unit.h +++ b/framework/unit.h @@ -10,6 +10,7 @@ #include "utils/ini_writer.h" #include "utils/payload_builder.h" #include "utils/payload_parser.h" +#include "rsc_enum.h" #define CHECK_TYPE(_unit, _driver) do { \ if ((_unit->driver) != (_driver)) \ @@ -33,11 +34,14 @@ struct unit { */ void *data; + /** Unit call sign for messages */ + uint8_t callsign; + /** Unit init status */ error_t status; - /** Unit call sign for messages */ - uint8_t callsign; + /** If RSC not avail. error is caught, the resource is stored here. */ + Resource failed_rsc; }; /** diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 575bbaa..3d6a8e1 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -355,7 +355,14 @@ static void export_unit_do(UlistEntry *li, IniWriter *iw) iw_section(iw, "%s:%s@%d", pUnit->driver->name, pUnit->name, (int)pUnit->callsign); if (pUnit->status != E_SUCCESS) { - iw_comment(iw, "!!! %s", error_get_message(pUnit->status)); + // special message for failed unit die to resource + if (pUnit->status == E_RESOURCE_NOT_AVAILABLE) { + iw_comment(iw, "!!! %s not available, already held by %s", + rsc_get_name(pUnit->failed_rsc), + rsc_get_owner_name(pUnit->failed_rsc)); + } else { + iw_comment(iw, "!!! %s", error_get_message(pUnit->status)); + } } pUnit->driver->cfgWriteIni(pUnit, iw); } From 05a568a27cdba1617182813b8323aefc4e2b2102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 17:32:37 +0100 Subject: [PATCH 06/13] ram savings by using new bitfield-based rsc alloc --- framework/resources.c | 107 ++++++++++++++++++++++++++------------ framework/rsc_enum.h | 59 +++++++++++++-------- framework/unit.h | 3 ++ framework/unit_registry.c | 12 +++++ framework/unit_registry.h | 8 +++ gex.mk | 2 +- platform/pin_utils.c | 8 +-- platform/platform.c | 32 ++++++------ utils/error.h | 2 +- 9 files changed, 157 insertions(+), 76 deletions(-) diff --git a/framework/resources.c b/framework/resources.c index 6e7b9b6..2ff7035 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -6,18 +6,15 @@ #include "unit.h" #include "resources.h" #include "pin_utils.h" +#include "unit_registry.h" static bool rsc_initialized = false; -// This takes quite a lot of space, we could use u8 and IDs instead if needed -struct resouce_slot { - const char *name; - Unit *owner; -} __attribute__((packed)); +static ResourceMap global_rscmap; -static struct resouce_slot resources[R_RESOURCE_COUNT]; +// here are the resource names for better debugging -// here are the resource names for better debugging (could also be removed if absolutely necessary) +// this list doesn't include GPIO names, they can be easily generated const char *const rsc_names[] = { #define X(res_name) #res_name, XX_RESOURCES @@ -27,16 +24,28 @@ const char *const rsc_names[] = { /** Get rsc name */ const char * rsc_get_name(Resource rsc) { - assert_param(rsc < R_RESOURCE_COUNT); + assert_param(rsc < RESOURCE_COUNT); + + static char gpionamebuf[4]; + if (rsc >= R_PA0) { + // we assume the returned value is not stored anywhere + // and is directly used in a sprintf call. + uint8_t index = rsc - R_PA0; + SNPRINTF(gpionamebuf, 4, "%c%d", 'A'+(index/16), index%16); + return gpionamebuf; + } + return rsc_names[rsc]; } /** Get rsc owner name */ const char * rsc_get_owner_name(Resource rsc) { - assert_param(rsc < R_RESOURCE_COUNT); - if (resources[rsc].owner == NULL) return "NULL"; - return resources[rsc].owner->name; + assert_param(rsc < RESOURCE_COUNT); + + Unit *pUnit = ureg_get_rsc_owner(rsc); + if (pUnit == NULL) return "NULL"; + return pUnit->name; } /** @@ -44,9 +53,10 @@ const char * rsc_get_owner_name(Resource rsc) */ void rsc_init_registry(void) { - for (int i = 0; i < R_RESOURCE_COUNT; i++) { - resources[i].owner = &UNIT_PLATFORM; + for(uint32_t i = 0; i < RSCMAP_LEN; i++) { + UNIT_PLATFORM.resources[i] = global_rscmap[i] = 0xFF; } + rsc_initialized = true; } @@ -60,22 +70,38 @@ void rsc_init_registry(void) error_t rsc_claim(Unit *unit, Resource rsc) { assert_param(rsc_initialized); - assert_param(rsc > R_NONE && rsc < R_RESOURCE_COUNT); + assert_param(rsc < RESOURCE_COUNT); assert_param(unit != NULL); - if (resources[rsc].owner) { - //TODO properly report to user + if (RSC_IS_HELD(global_rscmap, rsc)) { + // this whole branch is just reporting the error + + Unit *holder = ureg_get_rsc_owner(rsc); + + if (holder == NULL) { + // It must be one of the dummy built-in units + if (RSC_IS_HELD(UNIT_SYSTEM.resources, rsc)) + holder = &UNIT_SYSTEM; + else if (RSC_IS_HELD(UNIT_PLATFORM.resources, rsc)) + holder = &UNIT_SYSTEM; + } + + assert_param(holder != NULL); + dbg("ERROR!! Unit %s failed to claim resource %s, already held by %s!", unit->name, rsc_get_name(rsc), - rsc_get_owner_name(rsc)); + holder->name); unit->failed_rsc = rsc; return E_RESOURCE_NOT_AVAILABLE; } - resources[rsc].owner = unit; + // must claim both in global and in unit + RSC_CLAIM(global_rscmap, rsc); + RSC_CLAIM(unit->resources, rsc); + return E_SUCCESS; } @@ -90,8 +116,9 @@ error_t rsc_claim(Unit *unit, Resource rsc) error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1) { assert_param(rsc_initialized); - assert_param(rsc0 > R_NONE && rsc0 < R_RESOURCE_COUNT); - assert_param(rsc1 > R_NONE && rsc1 < R_RESOURCE_COUNT); + assert_param(rsc0 < RESOURCE_COUNT); + assert_param(rsc1 < RESOURCE_COUNT); + assert_param(rsc0 <= rsc1); assert_param(unit != NULL); for (int i = rsc0; i <= rsc1; i++) { @@ -125,11 +152,29 @@ error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) void rsc_free(Unit *unit, Resource rsc) { assert_param(rsc_initialized); - assert_param(rsc > R_NONE && rsc < R_RESOURCE_COUNT); + assert_param(rsc < RESOURCE_COUNT); + + if (RSC_IS_FREE(global_rscmap, rsc)) return; + + // free it in any unit that holds it + if (unit) { + if (RSC_IS_HELD(unit->resources, rsc)) { + RSC_FREE(unit->resources, rsc); + } + } else { + // Try to free it in any unit that may hold it + unit = ureg_get_rsc_owner(rsc); + if (unit == NULL) { + // try one of the built-in ones + if (RSC_IS_HELD(UNIT_SYSTEM.resources, rsc)) unit = &UNIT_SYSTEM; + else if (RSC_IS_HELD(UNIT_PLATFORM.resources, rsc)) unit = &UNIT_PLATFORM; + } - if (unit == NULL || resources[rsc].owner == unit) { - resources[rsc].owner = NULL; + if (unit != NULL) RSC_FREE(unit->resources, rsc); } + + // also free it in the global map + RSC_FREE(global_rscmap, rsc); } /** @@ -142,13 +187,12 @@ void rsc_free(Unit *unit, Resource rsc) void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1) { assert_param(rsc_initialized); - assert_param(rsc0 > R_NONE && rsc0 < R_RESOURCE_COUNT); - assert_param(rsc1 > R_NONE && rsc1 < R_RESOURCE_COUNT); + assert_param(rsc0 < RESOURCE_COUNT); + assert_param(rsc1 < RESOURCE_COUNT); + assert_param(rsc0 <= rsc1); for (int i = rsc0; i <= rsc1; i++) { - if (unit == NULL || resources[i].owner == unit) { - resources[i].owner = NULL; - } + rsc_free(unit, (Resource) i); } } @@ -162,9 +206,8 @@ void rsc_teardown(Unit *unit) assert_param(rsc_initialized); assert_param(unit != NULL); - for (int i = R_NONE+1; i < R_RESOURCE_COUNT; i++) { - if (resources[i].owner == unit) { - resources[i].owner = NULL; - } + for (uint32_t i = 0; i < RSCMAP_LEN; i++) { + global_rscmap[i] &= ~unit->resources[i]; + unit->resources[i] = 0; } } diff --git a/framework/rsc_enum.h b/framework/rsc_enum.h index 408e531..8344de4 100644 --- a/framework/rsc_enum.h +++ b/framework/rsc_enum.h @@ -7,7 +7,30 @@ // X macro: Resource name, #define XX_RESOURCES \ - X(NONE) \ + X(SPI1) X(SPI2) X(SPI3) \ + X(I2C1) X(I2C2) X(I2C3) \ + X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ + X(DAC1) X(DAC2) \ + X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ + X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ + X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \ + X(TIM15) X(TIM16) X(TIM17) \ + X(DMA1) X(DMA2) + +// Resources not used anywhere: +// X(I2S1) X(I2S2) X(I2S3) +// X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) +// X(CAN1) X(CAN2) +// X(TSC) +// X(DCMI) +// X(ETH) +// X(FSMC) +// X(SDIO) +// X(RNG) X(LCD) +// X(HDMI_CEC) +// X(COMP1) X(COMP2) X(COMP3) X(COMP4) X(COMP5) X(COMP6) X(COMP7) + +#define XX_RESOURCES_GPIO \ X(PA0) X(PA1) X(PA2) X(PA3) X(PA4) X(PA5) X(PA6) X(PA7) \ X(PA8) X(PA9) X(PA10) X(PA11) X(PA12) X(PA13) X(PA14) X(PA15) \ X(PB0) X(PB1) X(PB2) X(PB3) X(PB4) X(PB5) X(PB6) X(PB7) \ @@ -20,26 +43,6 @@ X(PE8) X(PE9) X(PE10) X(PE11) X(PE12) X(PE13) X(PE14) X(PE15) \ X(PF0) X(PF1) X(PF2) X(PF3) X(PF4) X(PF5) X(PF6) X(PF7) \ X(PF8) X(PF9) X(PF10) X(PF11) X(PF12) X(PF13) X(PF14) X(PF15) \ - X(SPI1) X(SPI2) X(SPI3) \ - X(I2C1) X(I2C2) X(I2C3) \ - X(I2S1) X(I2S2) X(I2S3) \ - X(ADC1) X(ADC2) X(ADC3) X(ADC4) \ - X(OPAMP1) X(OPAMP2) X(OPAMP3) X(OPAMP4) \ - X(DAC1) X(DAC2) \ - X(CAN1) X(CAN2) \ - X(TSC) \ - X(DCMI) \ - X(ETH) \ - X(FSMC) \ - X(SDIO) \ - X(COMP1) X(COMP2) X(COMP3) X(COMP4) X(COMP5) X(COMP6) X(COMP7) \ - X(HDMI_CEC) \ - X(USART1) X(USART2) X(USART3) X(USART4) X(USART5) X(USART6) \ - X(TIM1) X(TIM2) X(TIM3) X(TIM4) X(TIM5) \ - X(TIM6) X(TIM7) X(TIM8) X(TIM9) X(TIM10) X(TIM11) X(TIM12) X(TIM13) X(TIM14) \ - X(TIM15) X(TIM16) X(TIM17) \ - X(DMA1) X(DMA2) \ - X(RNG) X(LCD) // GPIOs are allocated whenever the pin is needed // (e.g. when used for SPI, the R_SPI resource as well as the corresponding R_GPIO resources must be claimed) @@ -70,8 +73,20 @@ typedef enum hw_resource Resource; enum hw_resource { #define X(res_name) R_##res_name, XX_RESOURCES + XX_RESOURCES_GPIO #undef X - R_RESOURCE_COUNT + R_NONE, + RESOURCE_COUNT = R_NONE, }; +#define RSCMAP_LEN ((RESOURCE_COUNT/8)+1) + +typedef uint8_t ResourceMap[RSCMAP_LEN]; + +#define RSC_IS_FREE(rscmap, rsc) (0 == (rscmap[((rsc)>>3)&0xFF] & (1<<((rsc)&0x7)))) +#define RSC_IS_HELD(rscmap, rsc) (!RSC_IS_FREE(rscmap, rsc)) +#define RSC_CLAIM(rscmap, rsc) do { rscmap[((rsc)>>3)&0xFF] |= (1<<((rsc)&0x7)); } while(0) +#define RSC_FREE(rscmap, rsc) do { rscmap[((rsc)>>3)&0xFF] &= ~(1<<((rsc)&0x7)); } while(0) + + #endif //GEX_F072_RSC_ENUM_H diff --git a/framework/unit.h b/framework/unit.h index 604cdee..3b530b1 100644 --- a/framework/unit.h +++ b/framework/unit.h @@ -42,6 +42,9 @@ struct unit { /** If RSC not avail. error is caught, the resource is stored here. */ Resource failed_rsc; + + /** Bit-map of held resources */ + ResourceMap resources; }; /** diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 3d6a8e1..79d7710 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -530,3 +530,15 @@ void ureg_report_active_units(TF_ID frame_id) } free(buff); } + +Unit *ureg_get_rsc_owner(Resource resource) +{ + UlistEntry *li = ulist_head; + while (li != NULL) { + if (RSC_IS_HELD(li->unit.resources, resource)) { + return &li->unit; + } + li = li->next; + } + return NULL; +} diff --git a/framework/unit_registry.h b/framework/unit_registry.h index c9c17e9..bb4ecbb 100644 --- a/framework/unit_registry.h +++ b/framework/unit_registry.h @@ -127,4 +127,12 @@ void ureg_deliver_unit_request(TF_Msg *msg); */ void ureg_report_active_units(TF_ID frame_id); +/** + * Get unit holding a resource, or NULL. + * + * @param resource + * @return unit + */ +Unit *ureg_get_rsc_owner(Resource resource); + #endif //GEX_UNIT_REGISTRY_H diff --git a/gex.mk b/gex.mk index 8eb9e9a..7bb2042 100644 --- a/gex.mk +++ b/gex.mk @@ -83,7 +83,7 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DVERBOSE_ASSERT=1 \ -DDEBUG_VFS=0 \ -DDEBUG_FLASH_WRITE=0 \ - -DVERBOSE_HARDFAULT=1 \ + -DVERBOSE_HARDFAULT=0 \ -DUSE_STACK_MONITOR=0 \ -DUSE_DEBUG_UART=1 diff --git a/platform/pin_utils.c b/platform/pin_utils.c index 5a25cb2..db1a50d 100644 --- a/platform/pin_utils.c +++ b/platform/pin_utils.c @@ -208,17 +208,17 @@ char * str_pinmask(uint16_t pins, char *buffer) } else { if (on) { if (!first) { - b += sprintf(b, ","); + b += SPRINTF(b, ","); } if (start == (uint32_t)(i+1)) { - b += sprintf(b, "%"PRIu32, start); + b += SPRINTF(b, "%"PRIu32, start); } else if (start == (uint32_t)(i+2)) { // exception for 2-long ranges - don't show as range - b += sprintf(b, "%"PRIu32",%"PRIu32, start, i + 1); + b += SPRINTF(b, "%"PRIu32",%"PRIu32, start, i + 1); } else { - b += sprintf(b, "%"PRIu32"-%"PRIu32, start, i + 1); + b += SPRINTF(b, "%"PRIu32"-%"PRIu32, start, i + 1); } first = false; on = false; diff --git a/platform/platform.c b/platform/platform.c index bfd439f..56ca9a3 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -83,13 +83,13 @@ void plat_init_resources(void) // Free all present resources { rsc_free(NULL, R_ADC1); - rsc_free(NULL, R_CAN1); - rsc_free_range(NULL, R_COMP1, R_COMP2); +// rsc_free(NULL, R_CAN1); +// rsc_free_range(NULL, R_COMP1, R_COMP2); rsc_free(NULL, R_DAC1); - rsc_free(NULL, R_HDMI_CEC); - rsc_free(NULL, R_TSC); +// rsc_free(NULL, R_HDMI_CEC); +// rsc_free(NULL, R_TSC); rsc_free_range(NULL, R_I2C1, R_I2C2); - rsc_free_range(NULL, R_I2S1, R_I2S2); +// rsc_free_range(NULL, R_I2S1, R_I2S2); rsc_free_range(NULL, R_SPI1, R_SPI2); rsc_free_range(NULL, R_TIM1, R_TIM3); rsc_free_range(NULL, R_TIM6, R_TIM7); @@ -131,18 +131,18 @@ void plat_init_resources(void) // Free all present resources { rsc_free_range(NULL, R_ADC1, R_ADC4); - rsc_free(NULL, R_CAN1); - rsc_free_range(NULL, R_COMP1, R_COMP7); - rsc_free(NULL, R_HDMI_CEC); +// rsc_free(NULL, R_CAN1); +// rsc_free_range(NULL, R_COMP1, R_COMP7); +// rsc_free(NULL, R_HDMI_CEC); rsc_free(NULL, R_DAC1); rsc_free_range(NULL, R_I2C1, R_I2C2); rsc_free_range(NULL, R_I2S2, R_I2S3); - rsc_free_range(NULL, R_OPAMP1, R_OPAMP4); +// rsc_free_range(NULL, R_OPAMP1, R_OPAMP4); rsc_free_range(NULL, R_SPI1, R_SPI3); rsc_free_range(NULL, R_TIM1, R_TIM4); rsc_free_range(NULL, R_TIM6, R_TIM8); rsc_free_range(NULL, R_TIM15, R_TIM17); - rsc_free(NULL, R_TSC); +// rsc_free(NULL, R_TSC); rsc_free_range(NULL, R_USART1, R_USART5); rsc_free_range(NULL, R_PA0, R_PA15); @@ -184,15 +184,15 @@ void plat_init_resources(void) // Free all present resources { rsc_free_range(NULL, R_ADC1, R_ADC3); - rsc_free_range(NULL, R_CAN1, R_CAN2); - rsc_free_range(NULL, R_COMP1, R_COMP7); +// rsc_free_range(NULL, R_CAN1, R_CAN2); +// rsc_free_range(NULL, R_COMP1, R_COMP7); rsc_free(NULL, R_DAC1); - rsc_free(NULL, R_DCMI); - rsc_free(NULL, R_ETH); - rsc_free(NULL, R_FSMC); +// rsc_free(NULL, R_DCMI); +// rsc_free(NULL, R_ETH); +// rsc_free(NULL, R_FSMC); rsc_free_range(NULL, R_I2C1, R_I2C3); rsc_free_range(NULL, R_I2S2, R_I2S3); - rsc_free(NULL, R_SDIO); +// rsc_free(NULL, R_SDIO); rsc_free_range(NULL, R_SPI1, R_SPI3); rsc_free_range(NULL, R_TIM1, R_TIM14); rsc_free_range(NULL, R_USART1, R_USART3); diff --git a/utils/error.h b/utils/error.h index 9b52727..1b294a5 100644 --- a/utils/error.h +++ b/utils/error.h @@ -58,7 +58,7 @@ X(BAD_KEY, "Unexpected config key") \ X(BAD_VALUE, "Bad config value") \ X(OUT_OF_MEM, "Not enough RAM") \ - X(RESOURCE_NOT_AVAILABLE, "Required pin / peripheral not available") + X(RESOURCE_NOT_AVAILABLE, NULL) // Keep in sync with the list error_message typedef enum { From d3d8400245ac552525e838345fb6d5ec3e2647f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 17:34:33 +0100 Subject: [PATCH 07/13] fix a bug in parsing SPI device --- units/spi/unit_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index df893b8..fc20030 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -86,7 +86,7 @@ static error_t USPI_loadIni(Unit *unit, const char *key, const char *value) if (streq(key, "device")) { priv->periph_num = (uint8_t) avr_atoi(value); } - if (streq(key, "remap")) { + else if (streq(key, "remap")) { priv->remap = (uint8_t) avr_atoi(value); } else if (streq(key, "prescaller")) { From ce895b3238c69b42ea3cc17a87849fb69f13874d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 17:46:48 +0100 Subject: [PATCH 08/13] added ini comment about remap meanigns for spi --- units/spi/unit_spi.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index fc20030..055c396 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -2,6 +2,7 @@ // Created by MightyPork on 2018/01/02. // +#include #include "comm/messages.h" #include "unit_base.h" #include "utils/avrlibc.h" @@ -123,14 +124,27 @@ static void USPI_writeIni(Unit *unit, IniWriter *iw) { struct priv *priv = unit->data; - // TODO show a legend for peripherals and remaps - + iw_cmt_newline(iw); iw_comment(iw, "Peripheral number (SPIx)"); iw_entry(iw, "device", "%d", (int)priv->periph_num); - iw_comment(iw, "SPI port remap (0,1,...)"); + // TODO show a legend for peripherals and remaps + iw_comment(iw, "Pin mappings (SCK,MISO,MOSI)"); +#if GEX_PLAT_F072_DISCOVERY + iw_comment(iw, " SPI1: (0) A5,A6,A7 (1) B3,B4,B5 (2) E13,E14,E15"); + iw_comment(iw, " SPI2: (0) B13,B14,B15 (1) D1,D3,D4"); +#elif GEX_PLAT_F103_BLUEPILL + #error "NO IMPL" +#elif GEX_PLAT_F303_DISCOVERY + #error "NO IMPL" +#elif GEX_PLAT_F407_DISCOVERY + #error "NO IMPL" +#else + #error "BAD PLATFORM!" +#endif iw_entry(iw, "remap", "%d", (int)priv->remap); + iw_cmt_newline(iw); iw_comment(iw, "Prescaller: 2,4,8,...,256"); iw_entry(iw, "prescaller", "%d", (int)priv->prescaller); @@ -146,10 +160,11 @@ static void USPI_writeIni(Unit *unit, IniWriter *iw) iw_comment(iw, "Use LSB-first bit order"); iw_entry(iw, "lsb-first", str_yn(priv->lsb_first)); - iw_comment(iw, "Slave Select port name"); + iw_cmt_newline(iw); + iw_comment(iw, "SS port name"); iw_entry(iw, "port", "%c", priv->ssn_port_name); - iw_comment(iw, "Slave select pins (comma separated, supports ranges)"); + iw_comment(iw, "SS pins (comma separated, supports ranges)"); iw_entry(iw, "pins", "%s", str_pinmask(priv->ssn_pins, unit_tmp512)); } From 6756b79ef4b0021193ee4cf71dccd4a3ae64d23b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 18:45:23 +0100 Subject: [PATCH 09/13] added automatic GPIO teardown, remap support to i2c, force error comments in ini if disabled --- framework/resources.c | 18 +++++----- framework/unit_registry.c | 26 +++++++++++---- platform/pin_utils.c | 11 ++++++ platform/pin_utils.h | 7 ++++ units/digital_in/unit_din.c | 18 +--------- units/digital_out/unit_dout.c | 20 +---------- units/i2c/unit_i2c.c | 61 ++++++++++++++++++++++++++++------ units/neopixel/unit_neopixel.c | 8 +---- units/spi/unit_spi.c | 20 ----------- 9 files changed, 98 insertions(+), 91 deletions(-) diff --git a/framework/resources.c b/framework/resources.c index 2ff7035..6898028 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -73,19 +73,12 @@ error_t rsc_claim(Unit *unit, Resource rsc) assert_param(rsc < RESOURCE_COUNT); assert_param(unit != NULL); + dbg("%s claims %s", unit->name, rsc_get_name(rsc)); + if (RSC_IS_HELD(global_rscmap, rsc)) { // this whole branch is just reporting the error Unit *holder = ureg_get_rsc_owner(rsc); - - if (holder == NULL) { - // It must be one of the dummy built-in units - if (RSC_IS_HELD(UNIT_SYSTEM.resources, rsc)) - holder = &UNIT_SYSTEM; - else if (RSC_IS_HELD(UNIT_PLATFORM.resources, rsc)) - holder = &UNIT_SYSTEM; - } - assert_param(holder != NULL); dbg("ERROR!! Unit %s failed to claim resource %s, already held by %s!", @@ -154,6 +147,8 @@ void rsc_free(Unit *unit, Resource rsc) assert_param(rsc_initialized); assert_param(rsc < RESOURCE_COUNT); + dbg("Free resource %s", rsc_get_name(rsc)); + if (RSC_IS_FREE(global_rscmap, rsc)) return; // free it in any unit that holds it @@ -197,7 +192,8 @@ void rsc_free_range(Unit *unit, Resource rsc0, Resource rsc1) } /** - * Tear down a unit - release all resources owned by the unit + * Tear down a unit - release all resources owned by the unit. + * Also de-init all GPIOs * * @param unit - unit to tear down; free only resources claimed by this unit */ @@ -206,6 +202,8 @@ void rsc_teardown(Unit *unit) assert_param(rsc_initialized); assert_param(unit != NULL); + deinit_unit_pins(unit); + for (uint32_t i = 0; i < RSCMAP_LEN; i++) { global_rscmap[i] &= ~unit->resources[i]; unit->resources[i] = 0; diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 79d7710..dda027f 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -355,14 +355,22 @@ static void export_unit_do(UlistEntry *li, IniWriter *iw) iw_section(iw, "%s:%s@%d", pUnit->driver->name, pUnit->name, (int)pUnit->callsign); if (pUnit->status != E_SUCCESS) { - // special message for failed unit die to resource - if (pUnit->status == E_RESOURCE_NOT_AVAILABLE) { - iw_comment(iw, "!!! %s not available, already held by %s", - rsc_get_name(pUnit->failed_rsc), - rsc_get_owner_name(pUnit->failed_rsc)); - } else { - iw_comment(iw, "!!! %s", error_get_message(pUnit->status)); + // temporarily force comments ON + bool sc = SystemSettings.ini_comments; + SystemSettings.ini_comments = true; + { + // special message for failed unit die to resource + if (pUnit->status == E_RESOURCE_NOT_AVAILABLE) { + iw_comment(iw, "!!! %s not available, already held by %s", + rsc_get_name(pUnit->failed_rsc), + rsc_get_owner_name(pUnit->failed_rsc)); + } + else { + iw_comment(iw, "!!! %s", error_get_message(pUnit->status)); + } + iw_cmt_newline(iw); } + SystemSettings.ini_comments = sc; } pUnit->driver->cfgWriteIni(pUnit, iw); } @@ -540,5 +548,9 @@ Unit *ureg_get_rsc_owner(Resource resource) } li = li->next; } + + if (RSC_IS_HELD(UNIT_SYSTEM.resources, resource)) return &UNIT_SYSTEM; + if (RSC_IS_HELD(UNIT_PLATFORM.resources, resource)) return &UNIT_PLATFORM; + return NULL; } diff --git a/platform/pin_utils.c b/platform/pin_utils.c index db1a50d..a9a5af0 100644 --- a/platform/pin_utils.c +++ b/platform/pin_utils.c @@ -260,3 +260,14 @@ uint16_t port_pack(uint16_t spread, uint16_t mask) } return result; } + +void deinit_unit_pins(Unit *unit) +{ + for (uint32_t rsc = R_PA0; rsc <= R_PF0; rsc++) { + if (RSC_IS_HELD(unit->resources, rsc)) { + GPIO_TypeDef *port = port_periphs[(rsc-R_PA0) / 16]; + uint32_t ll_pin = ll_pins[(rsc-R_PA0)%16]; + LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG); + } + } +} diff --git a/platform/pin_utils.h b/platform/pin_utils.h index ead2b34..a996cde 100644 --- a/platform/pin_utils.h +++ b/platform/pin_utils.h @@ -68,4 +68,11 @@ uint16_t port_spread(uint16_t packed, uint16_t mask); */ uint16_t port_pack(uint16_t spread, uint16_t mask); +/** + * Set all GPIO resources held by unit to analog + * + * @param unit - holding unit + */ +void deinit_unit_pins(Unit *unit); + #endif //GEX_PIN_UTILS_H diff --git a/units/digital_in/unit_din.c b/units/digital_in/unit_din.c index 01c321b..1071e57 100644 --- a/units/digital_in/unit_din.c +++ b/units/digital_in/unit_din.c @@ -161,23 +161,7 @@ static error_t DI_init(Unit *unit) /** Tear down the unit */ static void DI_deInit(Unit *unit) { - struct priv *priv = unit->data; - - if (unit->status == E_SUCCESS) { - assert_param(priv->port); - - bool suc = true; - uint16_t mask = 1; - for (int i = 0; i < 16; i++, mask <<= 1) { - if (priv->pins & mask) { - uint32_t ll_pin = pin2ll((uint8_t) i, &suc); - assert_param(suc); // this should never fail if we got this far - - // configure the pin as analog - LL_GPIO_SetPinMode(priv->port, ll_pin, LL_GPIO_MODE_ANALOG); - } - } - } + // pins are de-inited during teardown // Release all resources rsc_teardown(unit); diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index cb6f48d..5c1671d 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -151,25 +151,7 @@ static error_t DO_init(Unit *unit) /** Tear down the unit */ static void DO_deInit(Unit *unit) { - struct priv *priv = unit->data; - - // de-init the pins only if inited correctly - if (unit->status == E_SUCCESS) { - assert_param(priv->port); - - bool suc = true; - uint16_t mask = 1; - for (int i = 0; i < 16; i++, mask <<= 1) { - if (priv->pins & mask) { - - uint32_t ll_pin = pin2ll((uint8_t) i, &suc); - assert_param(suc); // this should never fail if we got this far - - // configure the pin as analog - LL_GPIO_SetPinMode(priv->port, ll_pin, LL_GPIO_MODE_ANALOG); - } - } - } + // pins are de-inited during teardown // Release all resources rsc_teardown(unit); diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index 796691a..ba5060b 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -2,6 +2,7 @@ // Created by MightyPork on 2018/01/02. // +#include #include "comm/messages.h" #include "unit_base.h" #include "utils/avrlibc.h" @@ -12,6 +13,8 @@ /** Private data structure */ struct priv { uint8_t periph_num; //!< 1 or 2 + uint8_t remap; //!< I2C remap option + bool anf; //!< Enable analog noise filter uint8_t dnf; //!< Enable digital noise filter (1-15 ... max spike width) uint8_t speed; //!< 0 - Standard, 1 - Fast, 2 - Fast+ @@ -63,6 +66,9 @@ static error_t UI2C_loadIni(Unit *unit, const char *key, const char *value) if (streq(key, "device")) { priv->periph_num = (uint8_t) avr_atoi(value); } + else if (streq(key, "remap")) { + priv->remap = (uint8_t) avr_atoi(value); + } else if (streq(key, "analog-filter")) { priv->anf = str_parse_yn(value, &suc); } @@ -88,6 +94,22 @@ static void UI2C_writeIni(Unit *unit, IniWriter *iw) iw_comment(iw, "Peripheral number (I2Cx)"); iw_entry(iw, "device", "%d", (int)priv->periph_num); + iw_comment(iw, "Pin mappings (SCL,SDA)"); +#if GEX_PLAT_F072_DISCOVERY + iw_comment(iw, " I2C1: (0) B6,B7 (1) B8,B9"); + iw_comment(iw, " I2C2: (0) B10,B11 (1) B13,B14"); +#elif GEX_PLAT_F103_BLUEPILL + #error "NO IMPL" +#elif GEX_PLAT_F303_DISCOVERY + #error "NO IMPL" +#elif GEX_PLAT_F407_DISCOVERY + #error "NO IMPL" +#else + #error "BAD PLATFORM!" +#endif + iw_entry(iw, "remap", "%d", (int)priv->remap); + + iw_cmt_newline(iw); iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+"); iw_entry(iw, "speed", "%d", (int)priv->speed); @@ -157,17 +179,38 @@ static error_t UI2C_init(Unit *unit) #if GEX_PLAT_F072_DISCOVERY // scl - 6 or 8 for I2C1, 10 for I2C2 // sda - 7 or 9 for I2C1, 11 for I2C2 - portname = 'B'; - if (priv->periph_num == 1) { - pin_scl = 8; - pin_sda = 9; + // I2C1 + if (priv->remap == 0) { + af_i2c = LL_GPIO_AF_1; + portname = 'B'; + pin_scl = 6; + pin_sda = 7; + } else if (priv->remap == 1) { + af_i2c = LL_GPIO_AF_1; + portname = 'B'; + pin_scl = 8; + pin_sda = 9; + } else { + return E_BAD_CONFIG; + } } else { - pin_scl = 10; - pin_sda = 12; + // I2C2 + if (priv->remap == 0) { + af_i2c = LL_GPIO_AF_1; + portname = 'B'; + pin_scl = 10; + pin_sda = 11; + } else if (priv->remap == 1) { + af_i2c = LL_GPIO_AF_5; + portname = 'B'; + pin_scl = 13; + pin_sda = 14; + } else { + return E_BAD_CONFIG; + } } - af_i2c = LL_GPIO_AF_1; if (priv->speed == 1) timing = 0x00301D2B; // Standard else if (priv->speed == 2) @@ -244,7 +287,6 @@ static void UI2C_deInit(Unit *unit) // de-init the pins & peripheral only if inited correctly if (unit->status == E_SUCCESS) { assert_param(priv->periph); - assert_param(priv->port); LL_I2C_DeInit(priv->periph); @@ -253,9 +295,6 @@ static void UI2C_deInit(Unit *unit) } else { __HAL_RCC_I2C2_CLK_DISABLE(); } - - LL_GPIO_SetPinMode(priv->port, priv->ll_pin_sda, LL_GPIO_MODE_ANALOG); - LL_GPIO_SetPinMode(priv->port, priv->ll_pin_scl, LL_GPIO_MODE_ANALOG); } // Release all resources diff --git a/units/neopixel/unit_neopixel.c b/units/neopixel/unit_neopixel.c index b5b1a21..585fdf2 100644 --- a/units/neopixel/unit_neopixel.c +++ b/units/neopixel/unit_neopixel.c @@ -121,13 +121,7 @@ static error_t Npx_init(Unit *unit) /** Tear down the unit */ static void Npx_deInit(Unit *unit) { - struct priv *priv = unit->data; - - if (unit->status == E_SUCCESS) { - assert_param(priv->port); - // configure the pin as analog - LL_GPIO_SetPinMode(priv->port, priv->ll_pin, LL_GPIO_MODE_ANALOG); - } + // pins are de-inited during teardown // Release all resources rsc_teardown(unit); diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index 055c396..a315d50 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -124,7 +124,6 @@ static void USPI_writeIni(Unit *unit, IniWriter *iw) { struct priv *priv = unit->data; - iw_cmt_newline(iw); iw_comment(iw, "Peripheral number (SPIx)"); iw_entry(iw, "device", "%d", (int)priv->periph_num); @@ -228,7 +227,6 @@ static error_t USPI_init(Unit *unit) // TODO #if GEX_PLAT_F072_DISCOVERY - // SPI1 - many options // sck, miso, mosi, af @@ -394,8 +392,6 @@ static void USPI_deInit(Unit *unit) // de-init the pins & peripheral only if inited correctly if (unit->status == E_SUCCESS) { assert_param(priv->periph); - assert_param(priv->spi_port); - assert_param(priv->ssn_port); LL_SPI_DeInit(priv->periph); @@ -404,22 +400,6 @@ static void USPI_deInit(Unit *unit) } else { __HAL_RCC_SPI2_CLK_DISABLE(); } - - LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_mosi, LL_GPIO_MODE_ANALOG); - LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_mosi, LL_GPIO_MODE_ANALOG); - LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_sck, LL_GPIO_MODE_ANALOG); - - // de-init all SSN pins - bool suc = true; - uint16_t mask = 1; - for (int i = 0; i < 16; i++, mask <<= 1) { - if (priv->ssn_pins & mask) { - uint32_t ll_pin = pin2ll((uint8_t) i, &suc); - assert_param(suc); - // configure the pin as analog - LL_GPIO_SetPinMode(priv->ssn_port, ll_pin, LL_GPIO_MODE_ANALOG); - } - } } // Release all resources From 6406475f48366d1be920d8549df462f29507999e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 19:17:25 +0100 Subject: [PATCH 10/13] some drying things up (GPIO init in particular) --- framework/resources.c | 9 ++++++ framework/resources.h | 1 + platform/pin_utils.c | 40 ++++++++++++++++++++++++ platform/pin_utils.h | 3 ++ units/i2c/unit_i2c.c | 45 +++++++++----------------- units/spi/unit_spi.c | 73 +++++++------------------------------------ 6 files changed, 79 insertions(+), 92 deletions(-) diff --git a/framework/resources.c b/framework/resources.c index 6898028..bcd985d 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -136,6 +136,15 @@ error_t rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) return E_SUCCESS; } +error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin) +{ + bool suc = true; + Resource rsc = pin2resource(port_name, pin, &suc); + if (!suc) return E_BAD_CONFIG; + TRY(rsc_claim(unit, rsc)); + return E_SUCCESS; +} + /** * Free a resource for other use * diff --git a/framework/resources.h b/framework/resources.h index 8290cf4..cd39c3c 100644 --- a/framework/resources.h +++ b/framework/resources.h @@ -13,6 +13,7 @@ void rsc_init_registry(void); +error_t rsc_claim_pin(Unit *unit, char port_name, uint8_t pin); error_t rsc_claim(Unit *unit, Resource rsc); error_t rsc_claim_range(Unit *unit, Resource rsc0, Resource rsc1); /** diff --git a/platform/pin_utils.c b/platform/pin_utils.c index a9a5af0..58a623c 100644 --- a/platform/pin_utils.c +++ b/platform/pin_utils.c @@ -271,3 +271,43 @@ void deinit_unit_pins(Unit *unit) } } } + + +error_t configure_gpio_alternate(char port_name, uint8_t pin_num, uint32_t af) +{ + bool suc = true; + GPIO_TypeDef *port = port2periph(port_name, &suc); + uint32_t ll_pin = pin2ll(pin_num, &suc); + if (!suc) return E_BAD_CONFIG; + + if (pin_num < 8) + LL_GPIO_SetAFPin_0_7(port, ll_pin, af); + else + LL_GPIO_SetAFPin_8_15(port, ll_pin, af); + + LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ALTERNATE); + + return E_SUCCESS; +} + +error_t configure_sparse_pins(char port_name, uint16_t mask, GPIO_TypeDef **port_dest, uint32_t mode, uint32_t otype) +{ + bool suc = true; + GPIO_TypeDef *port = port2periph(port_name, &suc); + if (!suc) return E_BAD_CONFIG; + + for (int i = 0; i < 16; i++) { + if (mask & (1<anf = pp_bool(pp); priv->dnf = pp_u8(pp); priv->speed = pp_u8(pp); + + if (version >= 1) { + priv->remap = pp_u8(pp); + } } /** Write to a binary buffer for storing in Flash */ @@ -47,12 +51,13 @@ static void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb) { struct priv *priv = unit->data; - pb_u8(pb, 0); // version + pb_u8(pb, 1); // version pb_u8(pb, priv->periph_num); pb_bool(pb, priv->anf); pb_u8(pb, priv->dnf); pb_u8(pb, priv->speed); + pb_u8(pb, priv->remap); } // ------------------------------------------------------------------------ @@ -229,32 +234,11 @@ static error_t UI2C_init(Unit *unit) #endif // first, we have to claim the pins - Resource r_sda = pin2resource(portname, pin_sda, &suc); - Resource r_scl = pin2resource(portname, pin_scl, &suc); - if (!suc) return E_BAD_CONFIG; - - TRY(rsc_claim(unit, r_sda)); - TRY(rsc_claim(unit, r_scl)); - - priv->port = port2periph(portname, &suc); - priv->ll_pin_scl = pin2ll(pin_scl, &suc); - priv->ll_pin_sda = pin2ll(pin_sda, &suc); - if (!suc) return E_BAD_CONFIG; - - // configure AF - if (pin_scl < 8) LL_GPIO_SetAFPin_0_7(priv->port, priv->ll_pin_scl, af_i2c); - else LL_GPIO_SetAFPin_8_15(priv->port, priv->ll_pin_scl, af_i2c); - - if (pin_sda < 8) LL_GPIO_SetAFPin_0_7(priv->port, priv->ll_pin_sda, af_i2c); - else LL_GPIO_SetAFPin_8_15(priv->port, priv->ll_pin_sda, af_i2c); - - LL_GPIO_SetPinMode(priv->port, priv->ll_pin_scl, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinMode(priv->port, priv->ll_pin_sda, LL_GPIO_MODE_ALTERNATE); - - // set as OpenDrain (this may not be needed - TODO check) - LL_GPIO_SetPinOutputType(priv->port, priv->ll_pin_scl, LL_GPIO_OUTPUT_OPENDRAIN); - LL_GPIO_SetPinOutputType(priv->port, priv->ll_pin_sda, LL_GPIO_OUTPUT_OPENDRAIN); + TRY(rsc_claim_pin(unit, portname, pin_sda)); + TRY(rsc_claim_pin(unit, portname, pin_scl)); + configure_gpio_alternate(portname, pin_sda, af_i2c); + configure_gpio_alternate(portname, pin_scl, af_i2c); if (priv->periph_num == 1) { __HAL_RCC_I2C1_CLK_ENABLE(); @@ -265,8 +249,7 @@ static error_t UI2C_init(Unit *unit) /* Disable the selected I2Cx Peripheral */ LL_I2C_Disable(priv->periph); LL_I2C_ConfigFilters(priv->periph, - priv->anf ? LL_I2C_ANALOGFILTER_ENABLE - : LL_I2C_ANALOGFILTER_DISABLE, + (priv->anf ? LL_I2C_ANALOGFILTER_ENABLE : LL_I2C_ANALOGFILTER_DISABLE), priv->dnf); LL_I2C_SetTiming(priv->periph, timing); diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index a315d50..d0b4b02 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -25,12 +25,7 @@ struct priv { uint16_t ssn_pins; //!< SSN pin mask SPI_TypeDef *periph; - GPIO_TypeDef *ssn_port; - GPIO_TypeDef *spi_port; - uint32_t ll_pin_miso; - uint32_t ll_pin_mosi; - uint32_t ll_pin_sck; }; // ------------------------------------------------------------------------ @@ -291,34 +286,13 @@ static error_t USPI_init(Unit *unit) #endif // first, we have to claim the pins - Resource r_mosi = pin2resource(spi_portname, pin_mosi, &suc); - Resource r_miso = pin2resource(spi_portname, pin_miso, &suc); - Resource r_sck = pin2resource(spi_portname, pin_sck, &suc); - if (!suc) return E_BAD_CONFIG; - - TRY(rsc_claim(unit, r_mosi)); - TRY(rsc_claim(unit, r_miso)); - TRY(rsc_claim(unit, r_sck)); - - priv->spi_port = port2periph(spi_portname, &suc); - priv->ll_pin_mosi = pin2ll(pin_mosi, &suc); - priv->ll_pin_miso = pin2ll(pin_miso, &suc); - priv->ll_pin_sck = pin2ll(pin_sck, &suc); - if (!suc) return E_BAD_CONFIG; - - // configure AF - if (pin_mosi < 8) LL_GPIO_SetAFPin_0_7(priv->spi_port, priv->ll_pin_mosi, af_spi); - else LL_GPIO_SetAFPin_8_15(priv->spi_port, priv->ll_pin_mosi, af_spi); + TRY(rsc_claim_pin(unit, spi_portname, pin_mosi)); + TRY(rsc_claim_pin(unit, spi_portname, pin_miso)); + TRY(rsc_claim_pin(unit, spi_portname, pin_sck)); - if (pin_miso < 8) LL_GPIO_SetAFPin_0_7(priv->spi_port, priv->ll_pin_miso, af_spi); - else LL_GPIO_SetAFPin_8_15(priv->spi_port, priv->ll_pin_miso, af_spi); - - if (pin_sck < 8) LL_GPIO_SetAFPin_0_7(priv->spi_port, priv->ll_pin_sck, af_spi); - else LL_GPIO_SetAFPin_8_15(priv->spi_port, priv->ll_pin_sck, af_spi); - - LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_mosi, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_miso, LL_GPIO_MODE_ALTERNATE); - LL_GPIO_SetPinMode(priv->spi_port, priv->ll_pin_sck, LL_GPIO_MODE_ALTERNATE); + configure_gpio_alternate(spi_portname, pin_mosi, af_spi); + configure_gpio_alternate(spi_portname, pin_miso, af_spi); + configure_gpio_alternate(spi_portname, pin_sck, af_spi); if (priv->periph_num == 1) { __HAL_RCC_SPI1_CLK_ENABLE(); @@ -328,22 +302,10 @@ static error_t USPI_init(Unit *unit) // configure SSN GPIOs { - priv->ssn_port = port2periph(priv->ssn_port_name, &suc); - if (!suc) return E_BAD_CONFIG; - // Claim all needed pins TRY(rsc_claim_gpios(unit, priv->ssn_port_name, priv->ssn_pins)); - - uint16_t mask = 1; - for (int i = 0; i < 16; i++, mask <<= 1) { - if (priv->ssn_pins & mask) { - uint32_t ll_pin = pin2ll((uint8_t) i, &suc); - LL_GPIO_SetPinMode(priv->ssn_port, ll_pin, LL_GPIO_MODE_OUTPUT); - LL_GPIO_SetPinOutputType(priv->ssn_port, ll_pin, LL_GPIO_OUTPUT_PUSHPULL); - LL_GPIO_SetPinSpeed(priv->ssn_port, ll_pin, LL_GPIO_SPEED_FREQ_HIGH); - } - } - + TRY(configure_sparse_pins(priv->ssn_port_name, priv->ssn_pins, &priv->ssn_port, + LL_GPIO_MODE_OUTPUT, LL_GPIO_OUTPUT_PUSHPULL)); // Set the initial state - all high priv->ssn_port->ODR &= priv->ssn_pins; } @@ -359,21 +321,10 @@ static error_t USPI_init(Unit *unit) dbg("Presc is %d", (int) presc); LL_SPI_SetBaudRatePrescaler(priv->periph, presc); - LL_SPI_SetClockPolarity(priv->periph, priv->cpol ? - LL_SPI_POLARITY_HIGH : - LL_SPI_POLARITY_LOW); - - LL_SPI_SetClockPhase(priv->periph, priv->cpha ? - LL_SPI_PHASE_1EDGE : - LL_SPI_PHASE_2EDGE); - - LL_SPI_SetTransferDirection(priv->periph, priv->tx_only ? - LL_SPI_HALF_DUPLEX_TX : - LL_SPI_FULL_DUPLEX); - - LL_SPI_SetTransferBitOrder(priv->periph, priv->lsb_first ? - LL_SPI_LSB_FIRST : - LL_SPI_MSB_FIRST); + LL_SPI_SetClockPolarity(priv->periph, priv->cpol ? LL_SPI_POLARITY_HIGH : LL_SPI_POLARITY_LOW); + LL_SPI_SetClockPhase(priv->periph, priv->cpha ? LL_SPI_PHASE_1EDGE : LL_SPI_PHASE_2EDGE); + LL_SPI_SetTransferDirection(priv->periph, priv->tx_only ? LL_SPI_HALF_DUPLEX_TX : LL_SPI_FULL_DUPLEX); + LL_SPI_SetTransferBitOrder(priv->periph, priv->lsb_first ? LL_SPI_LSB_FIRST : LL_SPI_MSB_FIRST); // TODO data size? From 8e07590cbee98901a240dc3a09c9586168ed4c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 6 Jan 2018 19:22:02 +0100 Subject: [PATCH 11/13] some cleaning --- units/digital_out/unit_dout.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index 5c1671d..46d4d51 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -125,18 +125,14 @@ static error_t DO_init(Unit *unit) // Claim all needed pins TRY(rsc_claim_gpios(unit, priv->port_name, priv->pins)); - uint16_t mask = 1; - for (int i = 0; i < 16; i++, mask <<= 1) { - if (priv->pins & mask) { + for (int i = 0; i < 16; i++) { + if (priv->pins & (1 << i)) { uint32_t ll_pin = pin2ll((uint8_t) i, &suc); // --- Init hardware --- LL_GPIO_SetPinMode(priv->port, ll_pin, LL_GPIO_MODE_OUTPUT); - - LL_GPIO_SetPinOutputType(priv->port, ll_pin, (priv->open_drain & mask) ? - LL_GPIO_OUTPUT_OPENDRAIN : - LL_GPIO_OUTPUT_PUSHPULL); - + LL_GPIO_SetPinOutputType(priv->port, ll_pin, + (priv->open_drain & (1 << i)) ? LL_GPIO_OUTPUT_OPENDRAIN : LL_GPIO_OUTPUT_PUSHPULL); LL_GPIO_SetPinSpeed(priv->port, ll_pin, LL_GPIO_SPEED_FREQ_HIGH); } } @@ -236,8 +232,6 @@ enum PinCmd_ { /** Handle a request message */ static error_t DO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { - struct priv *priv = unit->data; - uint16_t packed = pp_u16(pp); switch (command) { From 69fa263f453473de02928393ede06021db3b7c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 7 Jan 2018 00:32:00 +0100 Subject: [PATCH 12/13] working SPI unit --- units/digital_out/unit_dout.c | 4 +- units/i2c/unit_i2c.c | 4 +- units/spi/unit_spi.c | 118 +++++++++++++++++++++++++++------- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index 46d4d51..141a3db 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -223,7 +223,7 @@ error_t UU_DO_GetPinCount(Unit *unit, uint8_t *count) } enum PinCmd_ { - CMD_WRITE = 0, + CMD_QUERY = 0, CMD_SET = 1, CMD_CLEAR = 2, CMD_TOGGLE = 3, @@ -235,7 +235,7 @@ static error_t DO_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pay uint16_t packed = pp_u16(pp); switch (command) { - case CMD_WRITE: + case CMD_QUERY: return UU_DO_Write(unit, packed); case CMD_SET: diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index e101ec8..71b932b 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -291,7 +291,7 @@ static void UI2C_deInit(Unit *unit) // ------------------------------------------------------------------------ enum PinCmd_ { - CMD_WRITE = 0, + CMD_QUERY = 0, CMD_READ = 1, CMD_WRITE_REG = 2, CMD_READ_REG = 3, @@ -422,7 +422,7 @@ static error_t UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P switch (command) { /** Write byte(s) - addr:u16, byte(s) */ - case CMD_WRITE: + case CMD_QUERY: addr = pp_u16(pp); const uint8_t *bb = pp_tail(pp, &len); diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index d0b4b02..9164f21 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -3,6 +3,7 @@ // #include +#include #include "comm/messages.h" #include "unit_base.h" #include "utils/avrlibc.h" @@ -307,7 +308,7 @@ static error_t USPI_init(Unit *unit) TRY(configure_sparse_pins(priv->ssn_port_name, priv->ssn_pins, &priv->ssn_port, LL_GPIO_MODE_OUTPUT, LL_GPIO_OUTPUT_PUSHPULL)); // Set the initial state - all high - priv->ssn_port->ODR &= priv->ssn_pins; + priv->ssn_port->BSRR = priv->ssn_pins; } // Configure SPI - must be configured under reset @@ -318,15 +319,16 @@ static error_t USPI_init(Unit *unit) if (lz < 23) lz = 23; if (lz > 30) lz = 30; presc = (32 - lz - 2); - dbg("Presc is %d", (int) presc); - LL_SPI_SetBaudRatePrescaler(priv->periph, presc); + LL_SPI_SetBaudRatePrescaler(priv->periph, (presc<periph, priv->cpol ? LL_SPI_POLARITY_HIGH : LL_SPI_POLARITY_LOW); LL_SPI_SetClockPhase(priv->periph, priv->cpha ? LL_SPI_PHASE_1EDGE : LL_SPI_PHASE_2EDGE); LL_SPI_SetTransferDirection(priv->periph, priv->tx_only ? LL_SPI_HALF_DUPLEX_TX : LL_SPI_FULL_DUPLEX); LL_SPI_SetTransferBitOrder(priv->periph, priv->lsb_first ? LL_SPI_LSB_FIRST : LL_SPI_MSB_FIRST); - // TODO data size? + LL_SPI_SetNSSMode(priv->periph, LL_SPI_NSS_SOFT); + LL_SPI_SetDataWidth(priv->periph, LL_SPI_DATAWIDTH_8BIT); + LL_SPI_SetRxFIFOThreshold(priv->periph, LL_SPI_RX_FIFO_TH_QUARTER); // trigger RXNE on 1 byte LL_SPI_SetMode(priv->periph, LL_SPI_MODE_MASTER); } @@ -363,31 +365,102 @@ static void USPI_deInit(Unit *unit) // ------------------------------------------------------------------------ +static error_t spi_wait_until_flag(struct priv *priv, uint32_t flag, bool stop_state) +{ + uint32_t t_start = HAL_GetTick(); + while (((priv->periph->SR & flag) != 0) != stop_state) { + if (HAL_GetTick() - t_start > 10) { + return E_HW_TIMEOUT; + } + } + return E_SUCCESS; +} + +/** + * Perform a low level SPI transfer + * + * @param priv - private object of the SPI unit + * @param request - request buffer + * @param response - response buffer + * @param req_len - request len + * @param resp_skip - response skip bytes + * @param resp_len - response len + * @return success + */ +static error_t xfer_do(struct priv *priv, const uint8_t *request, + uint8_t *response, + uint32_t req_len, + uint32_t resp_skip, + uint32_t resp_len) +{ + // TODO this is slow, use DMA + + if (response == NULL) resp_len = 0; + + // avoid skip causing stretch beyond tx window if nothing is to be read back + if (resp_len == 0) resp_skip = 0; + + // in tx only mode, return zeros + if (priv->tx_only && resp_len>0) { + memset(response, 0, resp_len); + } + + uint8_t tb; + uint32_t end = MAX(req_len, resp_len + resp_skip); + for (uint32_t i = 0; i < end; i++) { + if (i < req_len) tb = *request++; + else tb = 0; + + TRY(spi_wait_until_flag(priv, SPI_SR_TXE, true)); + LL_SPI_TransmitData8(priv->periph, tb); + + if (!priv->tx_only) { + TRY(spi_wait_until_flag(priv, SPI_SR_RXNE, true)); + uint8_t rb = LL_SPI_ReceiveData8(priv->periph); + + if (resp_skip > 0) resp_skip--; + else if (resp_len > 0) { + resp_len--; + *response++ = rb; + } + } + } + return E_SUCCESS; +} error_t UU_SPI_Multicast(Unit *unit, uint16_t slaves, - const uint8_t *request, - uint32_t req_len) + const uint8_t *request, uint32_t req_len) { - // + struct priv *priv= unit->data; + uint16_t mask = port_spread(slaves, priv->ssn_pins); + priv->ssn_port->BRR = mask; + { + TRY(xfer_do(priv, request, NULL, req_len, 0, 0)); + } + priv->ssn_port->BSRR = mask; - return E_NOT_IMPLEMENTED; + return E_SUCCESS; } error_t UU_SPI_Write(Unit *unit, uint8_t slave_num, - const uint8_t *request, - uint8_t *response, - uint32_t req_len, - uint32_t resp_skip, - uint32_t resp_len) + const uint8_t *request, uint8_t *response, + uint32_t req_len, uint32_t resp_skip, uint32_t resp_len) { - // + struct priv *priv= unit->data; + + uint16_t mask = port_spread((uint16_t) (1 << slave_num), priv->ssn_pins); + priv->ssn_port->BRR = mask; + { + TRY(xfer_do(priv, request, response, req_len, resp_len, resp_skip)); + } + priv->ssn_port->BSRR = mask; - return E_NOT_IMPLEMENTED; + return E_SUCCESS; } enum PinCmd_ { - CMD_WRITE = 0, + CMD_QUERY = 0, CMD_MULTICAST = 1, }; @@ -405,9 +478,8 @@ static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P switch (command) { /** Write and read byte(s) - slave_num:u8, req_len:u16, resp_skip:u16, resp_len:u16, byte(s) */ - case CMD_WRITE: + case CMD_QUERY: slave = pp_u8(pp); - req_len = pp_u16(pp); resp_skip = pp_u16(pp); resp_len = pp_u16(pp); @@ -415,19 +487,21 @@ static error_t USPI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, P TRY(UU_SPI_Write(unit, slave, bb, (uint8_t *) unit_tmp512, - req_len, resp_skip, resp_len)); + len, resp_skip, resp_len)); - com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, resp_len); + // no response if we aren't reading + if (resp_len > 0) { + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, resp_len); + } return E_SUCCESS; /** Write byte(s) to multiple slaves - slaves:u16, req_len:u16, byte(s) */ case CMD_MULTICAST: slaves = pp_u16(pp); - req_len = pp_u16(pp); bb = pp_tail(pp, &len); - TRY(UU_SPI_Multicast(unit, slaves, bb, req_len)); + TRY(UU_SPI_Multicast(unit, slaves, bb, len)); return E_SUCCESS; default: From b5d9d146f9af331979a090381f0684c3386f6328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 7 Jan 2018 00:43:42 +0100 Subject: [PATCH 13/13] fixed the bug with botched deinig, caused by use of malloc instead of calloc --- framework/resources.c | 1 + framework/unit_registry.c | 9 ++++++--- platform/pin_utils.c | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/framework/resources.c b/framework/resources.c index bcd985d..5e19876 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -211,6 +211,7 @@ void rsc_teardown(Unit *unit) assert_param(rsc_initialized); assert_param(unit != NULL); + dbg("Tearing down unit %s", unit->name); deinit_unit_pins(unit); for (uint32_t i = 0; i < RSCMAP_LEN; i++) { diff --git a/framework/unit_registry.c b/framework/unit_registry.c index dda027f..5b90279 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -42,6 +42,7 @@ static int32_t unit_count = -1; void ureg_add_type(const UnitDriver *driver) { + bool suc = true; assert_param(driver != NULL); assert_param(driver->name != NULL); @@ -57,7 +58,9 @@ void ureg_add_type(const UnitDriver *driver) assert_param(driver->deInit != NULL); assert_param(driver->handleRequest != NULL); - UregEntry *re = malloc_s(sizeof(UregEntry)); + UregEntry *re = calloc_ck(1, sizeof(UregEntry), &suc); + assert_param(suc); + re->driver = driver; re->next = NULL; @@ -108,7 +111,7 @@ Unit *ureg_instantiate(const char *driver_name) while (re != NULL) { if (streq(re->driver->name, driver_name)) { // Create new list entry - UlistEntry *le = malloc_ck(sizeof(UlistEntry), &suc); + UlistEntry *le = calloc_ck(1, sizeof(UlistEntry), &suc); CHECK_SUC(); le->next = NULL; @@ -512,7 +515,7 @@ void ureg_report_active_units(TF_ID frame_id) msglen += count; // one byte per message for the callsign bool suc = true; - uint8_t *buff = malloc_ck(msglen, &suc); + uint8_t *buff = calloc_ck(1, msglen, &suc); if (!suc) { com_respond_error(frame_id, E_OUT_OF_MEM); return; diff --git a/platform/pin_utils.c b/platform/pin_utils.c index 58a623c..0ef321f 100644 --- a/platform/pin_utils.c +++ b/platform/pin_utils.c @@ -263,8 +263,9 @@ uint16_t port_pack(uint16_t spread, uint16_t mask) void deinit_unit_pins(Unit *unit) { - for (uint32_t rsc = R_PA0; rsc <= R_PF0; rsc++) { + for (uint32_t rsc = R_PA0; rsc <= R_PF15; rsc++) { if (RSC_IS_HELD(unit->resources, rsc)) { + dbg("Freeing pin %s", rsc_get_name((Resource)rsc)); GPIO_TypeDef *port = port_periphs[(rsc-R_PA0) / 16]; uint32_t ll_pin = ll_pins[(rsc-R_PA0)%16]; LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG);