From 9e7ae008b69227f3c4fb95af29b57f54044c4b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 3 Jan 2018 00:10:10 +0100 Subject: [PATCH 1/5] added unit and basic config --- framework/resources.c | 5 +- gex.mk | 5 +- platform/platform.c | 8 +- units/i2c/unit_i2c.c | 219 ++++++++++++++++++++++++++++++++++++++++++ units/i2c/unit_i2c.h | 12 +++ 5 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 units/i2c/unit_i2c.c create mode 100644 units/i2c/unit_i2c.h diff --git a/framework/resources.c b/framework/resources.c index 7c66a87..80b1047 100644 --- a/framework/resources.c +++ b/framework/resources.c @@ -92,14 +92,13 @@ bool rsc_claim_gpios(Unit *unit, char port_name, uint16_t pins) Resource rsc = pin2resource(port_name, (uint8_t) i, &suc); if (!suc) { unit->status = E_BAD_CONFIG; - - rsc_teardown(unit); +// rsc_teardown(unit); return false; } suc = rsc_claim(unit, rsc); if (!suc) { - rsc_teardown(unit); +// rsc_teardown(unit); return false; } } diff --git a/gex.mk b/gex.mk index a26d961..60554fa 100644 --- a/gex.mk +++ b/gex.mk @@ -10,6 +10,7 @@ GEX_SRC_DIR = \ User/units/test \ User/units/digital_out \ User/units/digital_in \ + User/units/i2c \ User/TinyFrame \ User/CWPack \ User/tasks @@ -80,8 +81,8 @@ else GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DUSE_FULL_ASSERT=1 \ -DVERBOSE_ASSERT=1 \ - -DDEBUG_VFS=0 \ - -DDEBUG_FLASH_WRITE=0 \ + -DDEBUG_VFS=1 \ + -DDEBUG_FLASH_WRITE=1 \ -DVERBOSE_HARDFAULT=1 \ -DUSE_STACK_MONITOR=1 \ -DUSE_DEBUG_UART=1 diff --git a/platform/platform.c b/platform/platform.c index f2f8cfc..0590f94 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -11,6 +11,7 @@ #include "units/digital_out/unit_dout.h" #include "units/digital_in/unit_din.h" #include "units/neopixel/unit_neopixel.h" +#include "units/i2c/unit_i2c.h" #include "units/test/unit_test.h" void plat_init_resources(void) @@ -22,8 +23,6 @@ void plat_init_resources(void) __HAL_RCC_GPIOE_CLK_ENABLE(); // --- Common unit drivers --- - ureg_add_type(&UNIT_DOUT); - ureg_add_type(&UNIT_DIN); #if HAVE_TEST_UNIT ureg_add_type(&UNIT_TEST); @@ -35,7 +34,6 @@ void plat_init_resources(void) // Platform STM32F103C8T6 Bluepill ($4 board from eBay) // Units supported by the platform (known to work correctly) - ureg_add_type(&UNIT_NEOPIXEL); // free all present resources { @@ -77,8 +75,10 @@ void plat_init_resources(void) __HAL_RCC_GPIOF_CLK_ENABLE(); // Units supported by the platform (known to work correctly) - // ureg_add_type(&UNIT_XYZ); + ureg_add_type(&UNIT_DOUT); + ureg_add_type(&UNIT_DIN); ureg_add_type(&UNIT_NEOPIXEL); + ureg_add_type(&UNIT_I2C); // Free all present resources { diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c new file mode 100644 index 0000000..4bc1ff0 --- /dev/null +++ b/units/i2c/unit_i2c.c @@ -0,0 +1,219 @@ +// +// Created by MightyPork on 2018/01/02. +// + +#include "comm/messages.h" +#include "unit_base.h" +#include "utils/avrlibc.h" +#include "unit_i2c.h" + +// I2C master + +/** Private data structure */ +struct priv { + uint8_t periph_num; //!< 1 or 2 + 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+ + + I2C_TypeDef *periph; +}; + +// ------------------------------------------------------------------------ + +/** Load from a binary buffer stored in Flash */ +static void UI2C_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->anf = pp_bool(pp); + priv->dnf = pp_u8(pp); + priv->speed = pp_u8(pp); +} + +/** Write to a binary buffer for storing in Flash */ +static void UI2C_writeBinary(Unit *unit, PayloadBuilder *pb) +{ + struct priv *priv = unit->data; + + pb_u8(pb, 0); // version + + pb_u8(pb, priv->periph_num); + pb_bool(pb, priv->anf); + pb_u8(pb, priv->dnf); + pb_u8(pb, priv->speed); +} + +// ------------------------------------------------------------------------ + +/** Parse a key-value pair from the INI file */ +static bool UI2C_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, "analog-filter")) { + priv->anf = str_parse_yn(value, &suc); + } + else if (streq(key, "digital-filter")) { + priv->dnf = (uint8_t) avr_atoi(value); + } + else if (streq(key, "speed")) { + priv->speed = (uint8_t) avr_atoi(value); + } + else { + return false; + } + + return suc; +} + +/** Generate INI file section for the unit */ +static void UI2C_writeIni(Unit *unit, IniWriter *iw) +{ + struct priv *priv = unit->data; + + iw_comment(iw, "Peripheral number (I2Cx)"); + iw_entry(iw, "device", "%d", (int)priv->periph_num); + + iw_comment(iw, "Speed: 1-Standard, 2-Fast, 3-Fast+"); + iw_entry(iw, "speed", "%d", (int)priv->speed); + + iw_comment(iw, "Analog noise filter enable (Y,N)"); + iw_entry(iw, "analog-filter", "%s", str_yn(priv->anf)); + + iw_comment(iw, "Digital noise filter bandwidth (0-15)"); + iw_entry(iw, "digital-filter", "%d", (int)priv->dnf); +} + +// ------------------------------------------------------------------------ + +/** Allocate data structure and set defaults */ +static bool UI2C_preInit(Unit *unit) +{ + bool suc = true; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); + CHECK_SUC(); + + // some defaults + priv->periph_num = 1; + priv->speed = 1; + priv->anf = true; + priv->dnf = 0; + + return true; +} + +/** Finalize unit set-up */ +static bool UI2C_init(Unit *unit) +{ + bool suc = true; + struct priv *priv = unit->data; + + if (!(priv->periph_num >= 1 && priv->periph_num <= 2)) { + unit->status = E_BAD_CONFIG; + dbg("!! Bad I2C periph"); + return false; + } + + if (!(priv->speed >= 1 && priv->speed <= 3)) { + unit->status = E_BAD_CONFIG; + dbg("!! Bad I2C speed"); + return false; + } + + if (priv->dnf > 15) { + unit->status = E_BAD_CONFIG; + dbg("!! Bad I2C DNF bw"); + return false; + } + + // assign and claim the peripheral + if (priv->periph_num == 1) { + suc = rsc_claim(unit, R_I2C1); + CHECK_SUC(); + priv->periph = I2C1; + } else { + suc = rsc_claim(unit, R_I2C2); + CHECK_SUC(); + priv->periph = I2C2; + } + + // TODO claim pins (config option to remap?) + + + return true; +} + +/** Tear down the unit */ +static void UI2C_deInit(Unit *unit) +{ + struct priv *priv = unit->data; + + // de-init the pins & peripheral only if inited correctly + if (unit->status == E_SUCCESS) { + // TODO + } + + // Release all resources + rsc_teardown(unit); + + // Free memory + free(unit->data); + unit->data = NULL; +} + +// ------------------------------------------------------------------------ + +enum PinCmd_ { + CMD_WRITE = 0, + CMD_READ = 1, +}; + +/** Handle a request message */ +static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +{ + struct priv *priv = unit->data; + + switch (command) { + case CMD_WRITE: + // + break; + + case CMD_READ: + // + break; + + default: + com_respond_bad_cmd(frame_id); + return false; + } + + return true; +} + +// ------------------------------------------------------------------------ + +/** Unit template */ +const UnitDriver UNIT_I2C = { + .name = "I2C", + .description = "I2C master", + // Settings + .preInit = UI2C_preInit, + .cfgLoadBinary = UI2C_loadBinary, + .cfgWriteBinary = UI2C_writeBinary, + .cfgLoadIni = UI2C_loadIni, + .cfgWriteIni = UI2C_writeIni, + // Init + .init = UI2C_init, + .deInit = UI2C_deInit, + // Function + .handleRequest = UI2C_handleRequest, +}; diff --git a/units/i2c/unit_i2c.h b/units/i2c/unit_i2c.h new file mode 100644 index 0000000..eb287a0 --- /dev/null +++ b/units/i2c/unit_i2c.h @@ -0,0 +1,12 @@ +// +// Created by MightyPork on 2018/01/02. +// + +#ifndef GEX_F072_UNIT_I2C_H +#define GEX_F072_UNIT_I2C_H + +#include "unit.h" + +extern const UnitDriver UNIT_I2C; + +#endif //GEX_F072_UNIT_I2C_H From f917427be41d32c2a577ca515e0c6f3bde9d08d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Wed, 3 Jan 2018 23:57:56 +0100 Subject: [PATCH 2/5] i2c write works --- framework/unit.c | 2 +- framework/unit.h | 3 +- gex.mk | 6 +- units/digital_in/unit_din.c | 10 +- units/digital_out/unit_dout.c | 6 +- units/i2c/unit_i2c.c | 210 +++++++++++++++++++++++++++++++++- utils/payload_parser.h | 2 +- vfs/file_stream.c | 10 +- vfs/vfs_manager.c | 78 ++++++------- vfs/virtual_fs.c | 6 +- vfs/virtual_fs.h | 4 + 11 files changed, 271 insertions(+), 66 deletions(-) diff --git a/framework/unit.c b/framework/unit.c index 5e20cca..872b596 100644 --- a/framework/unit.c +++ b/framework/unit.c @@ -6,7 +6,7 @@ #include "unit.h" #include "resources.h" -char unit_tmp64[64]; +char unit_tmp512[512]; // Abort partly inited unit void clean_failed_unit(Unit *unit) diff --git a/framework/unit.h b/framework/unit.h index bb85589..6ce4a5c 100644 --- a/framework/unit.h +++ b/framework/unit.h @@ -11,7 +11,8 @@ #include "utils/payload_builder.h" #include "utils/payload_parser.h" -extern char unit_tmp64[64]; // temporary static buffer +extern char unit_tmp512[512]; // temporary static buffer - not expected to be accessed asynchronously +// TODO add mutex? typedef struct unit Unit; typedef struct unit_driver UnitDriver; diff --git a/gex.mk b/gex.mk index 60554fa..405fc17 100644 --- a/gex.mk +++ b/gex.mk @@ -81,10 +81,10 @@ else GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DUSE_FULL_ASSERT=1 \ -DVERBOSE_ASSERT=1 \ - -DDEBUG_VFS=1 \ - -DDEBUG_FLASH_WRITE=1 \ + -DDEBUG_VFS=0 \ + -DDEBUG_FLASH_WRITE=0 \ -DVERBOSE_HARDFAULT=1 \ - -DUSE_STACK_MONITOR=1 \ + -DUSE_STACK_MONITOR=0 \ -DUSE_DEBUG_UART=1 endif diff --git a/units/digital_in/unit_din.c b/units/digital_in/unit_din.c index 9a862b1..c28f8f8 100644 --- a/units/digital_in/unit_din.c +++ b/units/digital_in/unit_din.c @@ -85,13 +85,13 @@ static void DI_writeIni(Unit *unit, IniWriter *iw) iw_entry(iw, "port", "%c", priv->port_name); iw_comment(iw, "Pins (comma separated, supports ranges)"); - iw_entry(iw, "pins", "%s", str_pinmask(priv->pins, unit_tmp64)); + iw_entry(iw, "pins", "%s", str_pinmask(priv->pins, unit_tmp512)); iw_comment(iw, "Pins with pull-up"); - iw_entry(iw, "pull-up", "%s", str_pinmask(priv->pullup, unit_tmp64)); + iw_entry(iw, "pull-up", "%s", str_pinmask(priv->pullup, unit_tmp512)); iw_comment(iw, "Pins with pull-down"); - iw_entry(iw, "pull-down", "%s", str_pinmask(priv->pulldown, unit_tmp64)); + iw_entry(iw, "pull-down", "%s", str_pinmask(priv->pulldown, unit_tmp512)); #if PLAT_NO_FLOATING_INPUTS iw_comment(iw, "NOTE: Pins use pull-up by default.\r\n"); @@ -206,9 +206,9 @@ static bool DI_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Payloa switch (command) { case CMD_READ:; - PayloadBuilder pb = pb_start((uint8_t*)unit_tmp64, 64, NULL); + PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 64, NULL); pb_u16(&pb, packed); - com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp64, pb_length(&pb)); + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, pb_length(&pb)); break; default: diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index 5d01d63..dfd26a4 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -81,13 +81,13 @@ static void DO_writeIni(Unit *unit, IniWriter *iw) iw_entry(iw, "port", "%c", priv->port_name); iw_comment(iw, "Pins (comma separated, supports ranges)"); - iw_entry(iw, "pins", "%s", str_pinmask(priv->pins, unit_tmp64)); + iw_entry(iw, "pins", "%s", str_pinmask(priv->pins, unit_tmp512)); iw_comment(iw, "Initially high pins"); - iw_entry(iw, "initial", "%s", str_pinmask(priv->initial, unit_tmp64)); + 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_tmp64)); + iw_entry(iw, "opendrain", "%s", str_pinmask(priv->open_drain, unit_tmp512)); } // ------------------------------------------------------------------------ diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index 4bc1ff0..d111c06 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -17,6 +17,10 @@ struct priv { uint8_t speed; //!< 0 - Standard, 1 - Fast, 2 - Fast+ I2C_TypeDef *periph; + + GPIO_TypeDef *port; + uint32_t ll_pin_scl; + uint32_t ll_pin_sda; }; // ------------------------------------------------------------------------ @@ -146,8 +150,92 @@ static bool UI2C_init(Unit *unit) priv->periph = I2C2; } - // TODO claim pins (config option to remap?) + // This is written for F072, other platforms will need adjustments + + char portname; + uint8_t pin_scl; + uint8_t pin_sda; + uint32_t af_i2c; + uint32_t timing; // magic constant from CubeMX + +#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; + } else { + pin_scl = 10; + pin_sda = 12; + } + + af_i2c = LL_GPIO_AF_1; + if (priv->speed == 1) + timing = 0x00301D2B; // Standard + else if (priv->speed == 2) + timing = 0x0000020B; // Fast + else + timing = 0x00000001; // Fast+ + +#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_sda = pin2resource(portname, pin_sda, &suc); + Resource r_scl = pin2resource(portname, pin_scl, &suc); + CHECK_SUC(); + rsc_claim(unit, r_sda); + rsc_claim(unit, r_scl); + CHECK_SUC(); + + GPIO_TypeDef *port = port2periph(portname, &suc); + uint32_t ll_pin_scl = pin2ll(pin_scl, &suc); + uint32_t ll_pin_sda = pin2ll(pin_sda, &suc); + CHECK_SUC(); + + // configure AF + if (pin_scl < 8) LL_GPIO_SetAFPin_0_7(port, ll_pin_scl, af_i2c); + else LL_GPIO_SetAFPin_8_15(port, ll_pin_scl, af_i2c); + + if (pin_sda < 8) LL_GPIO_SetAFPin_0_7(port, ll_pin_sda, af_i2c); + else LL_GPIO_SetAFPin_8_15(port, ll_pin_sda, af_i2c); + LL_GPIO_SetPinMode(port, ll_pin_scl, LL_GPIO_MODE_ALTERNATE); + LL_GPIO_SetPinMode(port, ll_pin_sda, LL_GPIO_MODE_ALTERNATE); + + // set as OpenDrain (this may not be needed - TODO check) + LL_GPIO_SetPinOutputType(port, ll_pin_scl, LL_GPIO_OUTPUT_OPENDRAIN); + LL_GPIO_SetPinOutputType(port, ll_pin_sda, LL_GPIO_OUTPUT_OPENDRAIN); + + + if (priv->periph_num == 1) { + __HAL_RCC_I2C1_CLK_ENABLE(); + } else { + __HAL_RCC_I2C2_CLK_ENABLE(); + } + + /* 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->dnf); + + LL_I2C_SetTiming(priv->periph, timing); + LL_I2C_DisableClockStretching(priv->periph); + LL_I2C_Enable(priv->periph); + + LL_I2C_DisableOwnAddress1(priv->periph); // OA not used + LL_I2C_SetMode(priv->periph, LL_I2C_MODE_I2C); // not using SMBus return true; } @@ -159,7 +247,16 @@ static void UI2C_deInit(Unit *unit) // de-init the pins & peripheral only if inited correctly if (unit->status == E_SUCCESS) { - // TODO + LL_I2C_DeInit(priv->periph); + + if (priv->periph_num == 1) { + __HAL_RCC_I2C1_CLK_DISABLE(); + } 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 @@ -177,18 +274,121 @@ enum PinCmd_ { CMD_READ = 1, }; +static void i2c_reset(struct priv *priv) +{ + LL_I2C_Disable(priv->periph); + HAL_Delay(1); + LL_I2C_Enable(priv->periph); +} + +static bool i2c_wait_until_flag(struct priv *priv, TF_ID frame_id, uint32_t flag, + bool stop_state, const char *msg) +{ + uint32_t t_start = HAL_GetTick(); + while (((priv->periph->ISR & flag)!=0) != stop_state) { + if (HAL_GetTick() - t_start > 10) { + com_respond_err(frame_id, msg); + i2c_reset(priv); + return false; + } + } +} + /** Handle a request message */ static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { struct priv *priv = unit->data; + uint8_t addrsize; // 7 or 10 + uint16_t addr; + uint32_t len; + uint32_t t_start; + switch (command) { - case CMD_WRITE: - // + case CMD_WRITE:; + addrsize = pp_u8(pp); // 7 or 10 + addr = pp_u16(pp); + + t_start = HAL_GetTick(); + while (LL_I2C_IsActiveFlag_BUSY(priv->periph)) { + if (HAL_GetTick() - t_start > 10) { + com_respond_err(frame_id, "BUSY TIMEOUT"); + i2c_reset(priv); + return false; + } + } +// if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_BUSY, 0, "BUSY TIMEOUT")) return false; + + uint32_t chunk_remain; + while (pp_length(pp) > 0) { + len = pp_length(pp); + chunk_remain = (uint8_t) ((len > 255) ? 255 : len), // if more than 255, first chunk is 255 + LL_I2C_HandleTransfer(priv->periph, + (addrsize == 7) ? addr << 1 : addr, // Address must be shifted to left by one if 7-bit mode is used. Bit 0 serves for R/W flag + (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT, // translate to LL bitfields + (uint32_t) chunk_remain, + (len > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk + LL_I2C_GENERATE_START_WRITE); + + for (; chunk_remain > 0; chunk_remain--) { + t_start = HAL_GetTick(); + while (!LL_I2C_IsActiveFlag_TXIS(priv->periph)) { + if (HAL_GetTick() - t_start > 10) { + com_respond_err(frame_id, "TXIS TIMEOUT"); + i2c_reset(priv); + return false; + } + } + + uint8_t byte = pp_u8(pp); + LL_I2C_TransmitData8(priv->periph, byte); + } + } + + t_start = HAL_GetTick(); + while (!LL_I2C_IsActiveFlag_STOP(priv->periph)) { + if (HAL_GetTick() - t_start > 10) { + com_respond_err(frame_id, "STOPF TIMEOUT"); + i2c_reset(priv); + return false; + } + } + break; case CMD_READ: - // + addrsize = pp_u8(pp); // 7 or 10 + addr = pp_u16(pp); + len = pp_u16(pp); + + // TODO support > 255? + if (len > 256) { + com_respond_err(frame_id, "TOO LONG"); + return false; + } + + LL_I2C_HandleTransfer(priv->periph, + (addrsize == 7) ? addr << 1 : addr, + addrsize == 7 ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT, + (uint32_t) pp_length(pp), + LL_I2C_MODE_AUTOEND, // ? + LL_I2C_GENERATE_START_READ); + + for (uint32_t i = 0; i < len; i++) { + t_start = HAL_GetTick(); + while (!LL_I2C_IsActiveFlag_RXNE(priv->periph)) { + // wait for RXNE + if (HAL_GetTick() - t_start > 10) { + com_respond_err(frame_id, "RX TIMEOUT"); + return false; + } + } + + uint8_t b = LL_I2C_ReceiveData8(priv->periph); + unit_tmp512[i] = b; + } + + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, len); break; default: diff --git a/utils/payload_parser.h b/utils/payload_parser.h index cddab1b..62d5ac0 100644 --- a/utils/payload_parser.h +++ b/utils/payload_parser.h @@ -66,7 +66,7 @@ struct PayloadParser_ { // --- utilities --- /** Get remaining length */ -#define pp_length(pp) ((pp)->end - (pp)->current) +#define pp_length(pp) (uint32_t)((pp)->end - (pp)->current) /** Reset the current pointer to start */ #define pp_rewind(pp) do { pp->current = pp->start; } while (0) diff --git a/vfs/file_stream.c b/vfs/file_stream.c index a33ece2..08580bb 100644 --- a/vfs/file_stream.c +++ b/vfs/file_stream.c @@ -219,10 +219,10 @@ static error_t write_conf(void *state, const uint8_t *data, uint32_t size) conf_state_t *conf = state; conf->file_pos += size; - vfs_printf("Writing INI - RX %d bytes", size); - vfs_printf_nonl("\033[92m", 5); - vfs_printf_nonl((const char *) data, size); - vfs_printf_nonl("\033[0m\r\n", 6); + vfs_printf("Writing INI - RX %d bytes", (int)size); + vfs_puts("\033[92m"); + vfs_putsn((const char *) data, size); + vfs_puts("\033[0m\r\n"); ini_parse((const char *) data, size); @@ -233,7 +233,7 @@ static error_t write_conf(void *state, const uint8_t *data, uint32_t size) static error_t close_conf(void *state) { conf_state_t *conf = state; - vfs_printf("Close INI, total bytes = %d", conf->file_pos); + vfs_printf("Close INI, total bytes = %d", (int)conf->file_pos); ini_parse_end(); settings_load_ini_end(); diff --git a/vfs/vfs_manager.c b/vfs/vfs_manager.c index f6fb3d3..2aa238e 100644 --- a/vfs/vfs_manager.c +++ b/vfs/vfs_manager.c @@ -134,7 +134,7 @@ static void transfer_update_state(error_t status); void vfs_mngr_fs_enable(bool enable) { sync_lock(); - vfs_printf("Enable = %d", enable); + vfs_printf("Enable = %d", (int)enable); if (enable) { if (VFS_MNGR_STATE_DISCONNECTED == vfs_state_next) { @@ -208,8 +208,8 @@ void vfs_mngr_periodic(uint32_t elapsed_ms) } vfs_printf("vfs_mngr_periodic()\r\n"); - vfs_printf(" time_usb_idle=%i\r\n", time_usb_idle); - vfs_printf(" transfer_state=%i\r\n", file_transfer_state.transfer_state); + vfs_printf(" time_usb_idle=%i\r\n", (int)time_usb_idle); + vfs_printf(" transfer_state=%i\r\n", (int)file_transfer_state.transfer_state); // Transition to new state vfs_state_local_prev = vfs_state; vfs_state = vfs_state_next; @@ -229,7 +229,7 @@ void vfs_mngr_periodic(uint32_t elapsed_ms) time_usb_idle = 0; sync_unlock(); // Processing when leaving a state - vfs_printf(" state %i->%i\r\n", vfs_state_local_prev, vfs_state_local); + vfs_printf(" state %i->%i\r\n", (int)vfs_state_local_prev, (int)vfs_state_local); bool want_notify_only = false; // Use this if the transfer timed out and we dont need full reconnect switch (vfs_state_local_prev) { @@ -331,7 +331,7 @@ void vfs_if_usbd_msc_read_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_se void vfs_if_usbd_msc_write_sect(uint32_t sector, uint8_t *buf, uint32_t num_of_sectors) { sync_assert_usb_thread(); - vfs_printf("\033[32mWRITE @ %d, len %d\033[0m", sector, num_of_sectors); + vfs_printf("\033[32mWRITE @ %d, len %d\033[0m", (int)sector, (int)num_of_sectors); if (buf[0] == 0xF8 && buf[1] == 0xFF && buf[2] == 0xFF && buf[3] == 0xFF) { vfs_printf("Discard write of F8,FF,FF,FF"); return; @@ -428,7 +428,7 @@ static void switch_to_new_file(stream_type_t stream, uint32_t start_sector, bool // Callback to handle changes to the root directory. Should be used with vfs_set_file_change_callback static void file_change_handler(const vfs_filename_t filename, vfs_file_change_t change, vfs_file_t file, vfs_file_t new_file_data) { - vfs_printf("\033[33m@file_change_handler\033[0m (name=%*s, file=%p, ftp=%p, change=%i)\r\n", 11, filename, file, change); + vfs_printf("\033[33m@file_change_handler\033[0m (name=%*s, file=%p, change=%i)\r\n", 11, filename, file, (int)change); vfs_user_file_change_handler(filename, change, file, new_file_data); if (TRASNFER_FINISHED == file_transfer_state.transfer_state) { @@ -490,10 +490,10 @@ static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_ { stream_type_t stream; uint32_t size; - vfs_printf("\033[33m@file_data_handler\033[0m (sec=%d, num=%d)", sector, num_of_sectors); + vfs_printf("\033[33m@file_data_handler\033[0m (sec=%d, num=%d)", (int)sector, (int)num_of_sectors); if (sector <= 1) { - vfs_printf("Discard write to sector %d", sector); + vfs_printf("Discard write to sector %d", (int)sector); return; } @@ -521,7 +521,7 @@ static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_ // sectors must be in order if (sector != file_transfer_state.file_next_sector) { - vfs_printf("file_data_handler BAD sector=%i\r\n", sector); + vfs_printf("file_data_handler BAD sector=%i\r\n", (int)sector); // Try to find what file this belongs to, if any // OS sometimes first writes the FAT and then the individual files, @@ -544,7 +544,7 @@ static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_ if (sector >= file_transfer_state.start_sector && sector < file_transfer_state.file_next_sector) { vfs_printf(" sector out of order! lowest ooo = %i\r\n", - file_transfer_state.last_ooo_sector); + (int)file_transfer_state.last_ooo_sector); if (VFS_INVALID_SECTOR == file_transfer_state.last_ooo_sector) { file_transfer_state.last_ooo_sector = sector; @@ -572,12 +572,12 @@ static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_ } vfs_printf(" discarding data - size transferred=0x%x\r\n", - file_transfer_state.size_transferred); + (int)file_transfer_state.size_transferred); - vfs_printf_nonl("\033[31m", 5); + vfs_puts("\033[31m"); // FIXME this seems wrong - vfs_printf_nonl((const char *) buf, VFS_SECTOR_SIZE * num_of_sectors); - vfs_printf_nonl("\033[0m\r\n", 6); + vfs_putsn((const char *) buf, VFS_SECTOR_SIZE * num_of_sectors); + vfs_puts("\033[0m\r\n"); return; } else { @@ -591,13 +591,13 @@ static void file_data_handler(uint32_t sector, const uint8_t *buf, uint32_t num_ // If stream processing is done then discard the data if (file_transfer_state.stream_finished) { - vfs_printf("vfs_manager file_data_handler\r\n sector=%i, size=%i\r\n", sector, size); + vfs_printf("vfs_manager file_data_handler\r\n sector=%i, size=%i\r\n", (int)sector, (int)size); vfs_printf(" discarding data - size transferred=0x%x\r\n", - file_transfer_state.size_transferred); + (int)file_transfer_state.size_transferred); - vfs_printf_nonl("\033[31m", 5); - vfs_printf_nonl((const char *) buf, VFS_SECTOR_SIZE * num_of_sectors); - vfs_printf_nonl("\033[0m\r\n", 6); + vfs_puts("\033[31m"); + vfs_putsn((const char *) buf, VFS_SECTOR_SIZE * num_of_sectors); + vfs_puts("\033[0m\r\n"); transfer_update_state(E_SUCCESS); return; @@ -671,7 +671,7 @@ void abort_remount(void) // Update the tranfer state with file information static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, uint32_t size, stream_type_t stream) { - vfs_printf("\033[33m@transfer_update_file_info\033[0m (file=%p, start_sector=%i, size=%i)\r\n", file, start_sector, size); + vfs_printf("\033[33m@transfer_update_file_info\033[0m (file=%p, start_sector=%i, size=%i)\r\n", file, (int)start_sector, (int)size); if (TRASNFER_FINISHED == file_transfer_state.transfer_state) { trap("xfer already finished"); @@ -692,7 +692,7 @@ static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, ui file_transfer_state.start_sector = start_sector; if (start_sector != VFS_INVALID_SECTOR) { - vfs_printf(" start_sector=%i\r\n", start_sector); + vfs_printf(" start_sector=%i\r\n", (int)start_sector); } } @@ -701,13 +701,13 @@ static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, ui file_transfer_state.stream = stream; if (stream != STREAM_TYPE_NONE) { - vfs_printf(" stream=%i\r\n", stream); + vfs_printf(" stream=%i\r\n", (int)stream); } } // Check - File size must either grow or be smaller than the size already transferred if ((size < file_transfer_state.file_size) && (size < file_transfer_state.size_transferred)) { - vfs_printf(" error: file size changed from %i to %i\r\n", file_transfer_state.file_size, size); + vfs_printf(" error: file size changed from %i to %i\r\n", (int)file_transfer_state.file_size, (int)size); // this is probably a new file trap("File shrinks");//XXX switch_to_new_file(stream, start_sector, true); @@ -715,7 +715,7 @@ static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, ui // Check - Starting sector must be the same - this is optional for file info since it may not be present initially if ((VFS_INVALID_SECTOR != start_sector) && (start_sector != file_transfer_state.start_sector)) { - vfs_printf(" error: starting sector changed from %i to %i\r\n", file_transfer_state.start_sector, start_sector); + vfs_printf(" error: starting sector changed from %i to %i\r\n", (int)file_transfer_state.start_sector, (int)start_sector); // this is probably a new file dbg("WARN! Changed start offset"); @@ -733,7 +733,7 @@ static void transfer_update_file_info(vfs_file_t file, uint32_t start_sector, ui // Update values - Size is the only value that can change file_transfer_state.file_size = size; - vfs_printf(" updated size=%i\r\n", size); + vfs_printf(" updated size=%i\r\n", (int)size); transfer_update_state(E_SUCCESS); } @@ -757,11 +757,11 @@ static void transfer_stream_open(stream_type_t stream, uint32_t start_sector) assert_param(!file_transfer_state.stream_open); assert_param(start_sector != VFS_INVALID_SECTOR); vfs_printf("\033[33m@transfer_stream_open\033[0m (stream=%i, start_sector=%i)\r\n", - stream, start_sector); + (int)stream, (int)start_sector); // Check - Starting sector must be the same if (start_sector != file_transfer_state.start_sector && file_transfer_state.start_sector != VFS_INVALID_SECTOR) { - vfs_printf(" error: starting sector changed from %i to %i\r\n", file_transfer_state.start_sector, start_sector); + vfs_printf(" error: starting sector changed from %i to %i\r\n", (int)file_transfer_state.start_sector, (int)start_sector); // this is probably a new file switch_to_new_file(stream, start_sector, false); file_transfer_state.start_sector = VFS_INVALID_SECTOR; @@ -769,7 +769,7 @@ static void transfer_stream_open(stream_type_t stream, uint32_t start_sector) // Check - stream must be the same if (stream != file_transfer_state.stream && file_transfer_state.stream != STREAM_TYPE_NONE) { - vfs_printf(" error: changed types during tranfer from %i to %i\r\n", stream, file_transfer_state.stream); + vfs_printf(" error: changed types during tranfer from %i to %i\r\n", (int)stream, (int)file_transfer_state.stream); // this is probably a new file switch_to_new_file(stream, start_sector, false); file_transfer_state.start_sector = VFS_INVALID_SECTOR; @@ -780,7 +780,7 @@ static void transfer_stream_open(stream_type_t stream, uint32_t start_sector) file_transfer_state.start_sector = start_sector; if (start_sector != VFS_INVALID_SECTOR) { - vfs_printf(" start_sector=%i\r\n", start_sector); + vfs_printf(" start_sector=%i\r\n", (int)start_sector); } } @@ -789,13 +789,13 @@ static void transfer_stream_open(stream_type_t stream, uint32_t start_sector) file_transfer_state.stream = stream; if (stream != STREAM_TYPE_NONE) { - vfs_printf(" stream=%i\r\n", stream); + vfs_printf(" stream=%i\r\n", (int)stream); } } // Open stream status = stream_open(stream); - vfs_printf(" stream_open stream=%i ret %i\r\n", stream, status); + vfs_printf(" stream_open stream=%i ret %i\r\n", (int)stream, (int)status); if (E_SUCCESS == status) { file_transfer_state.file_next_sector = start_sector; @@ -810,9 +810,9 @@ static void transfer_stream_open(stream_type_t stream, uint32_t start_sector) static void transfer_stream_data(uint32_t sector, const uint8_t *data, uint32_t size) { error_t status; - vfs_printf("\033[33m@transfer_stream_data\033[0m (sector=%i, size=%i)\r\n", sector, size); + vfs_printf("\033[33m@transfer_stream_data\033[0m (sector=%i, size=%i)\r\n", (int)sector, (int)size); vfs_printf(" size processed=0x%x, data=%x,%x,%x,%x,...\r\n", - file_transfer_state.size_processed, data[0], data[1], data[2], data[3]); + (int)file_transfer_state.size_processed, data[0], data[1], data[2], data[3]); if (file_transfer_state.stream_finished) { trap("Stream already closed"); @@ -822,13 +822,13 @@ static void transfer_stream_data(uint32_t sector, const uint8_t *data, uint32_t assert_param(size % VFS_SECTOR_SIZE == 0); assert_param(file_transfer_state.stream_open); status = stream_write((uint8_t *) data, size); - vfs_printf(" stream_write ret=%i\r\n", status); + vfs_printf(" stream_write ret=%i\r\n", (int)status); if (E_SUCCESS_DONE == status) { // Override status so E_SUCCESS_DONE // does not get passed into transfer_update_state status = stream_close(); - vfs_printf(" stream_close ret=%i\r\n", status); + vfs_printf(" stream_close ret=%i\r\n", (int)status); file_transfer_state.stream_open = false; file_transfer_state.stream_finished = true; file_transfer_state.stream_optional_finish = true; @@ -921,11 +921,11 @@ static void transfer_update_state(error_t status) if (TRASNFER_FINISHED == file_transfer_state.transfer_state) { vfs_printf("vfs_manager transfer_update_state(status=%i)\r\n", status); vfs_printf(" file=%p, start_sect= %i, size=%i\r\n", - file_transfer_state.file_to_program, file_transfer_state.start_sector, - file_transfer_state.file_size); + file_transfer_state.file_to_program, (int)file_transfer_state.start_sector, + (int)file_transfer_state.file_size); vfs_printf(" stream=%i, size_processed=%i, opt_finish=%i, timeout=%i\r\n", - file_transfer_state.stream, file_transfer_state.size_processed, - file_transfer_state.file_info_optional_finish, transfer_timeout); + (int)file_transfer_state.stream, (int)file_transfer_state.size_processed, + (int)file_transfer_state.file_info_optional_finish, (int)transfer_timeout); // Close the file stream if it is open if (file_transfer_state.stream_open) { diff --git a/vfs/virtual_fs.c b/vfs/virtual_fs.c index 4fd3a6e..9d37e60 100644 --- a/vfs/virtual_fs.c +++ b/vfs/virtual_fs.c @@ -555,7 +555,7 @@ void vfs_write(uint32_t requested_sector, const uint8_t *buf, uint32_t num_secto set_init_done(); - vfs_printf("vfs_write - at sector %d, count %d", requested_sector, num_sectors); + vfs_printf("vfs_write - at sector %d, count %d", (int)requested_sector, (int)num_sectors); for (i = 0; i < virtual_media_idx; i++) { uint32_t vm_sectors = virtual_media[i].length / VFS_SECTOR_SIZE; uint32_t vm_start = current_sector; @@ -582,7 +582,7 @@ void vfs_write(uint32_t requested_sector, const uint8_t *buf, uint32_t num_secto // Move to the next virtual media entry current_sector += vm_sectors; } - if (num_sectors > 0) vfs_printf("Failed to find place for writing, remain %d secs to write.", num_sectors); + if (num_sectors > 0) vfs_printf("Failed to find place for writing, remain %d secs to write.", (int)num_sectors); } static uint32_t read_zero(uint32_t sector_offset, uint8_t *data, uint32_t num_sectors) @@ -788,7 +788,7 @@ static void set_init_done(void) bool vfs_find_file(uint32_t start_sector, vfs_filename_t *destFilename, vfs_file_t **destFile) { - vfs_printf("Looking for file at %d", start_sector); + vfs_printf("Looking for file at %d", (int)start_sector); for (int i = 0; i < 32; i++) { FatDirectoryEntry_t *f = &dir_current.f[i]; if (f->attributes == VFS_FILE_ATTR_LFN) continue; diff --git a/vfs/virtual_fs.h b/vfs/virtual_fs.h index 155587a..5b75b41 100644 --- a/vfs/virtual_fs.h +++ b/vfs/virtual_fs.h @@ -31,9 +31,13 @@ extern "C" { #if DEBUG_VFS #define vfs_printf(...) do { dbg(__VA_ARGS__); } while(0) #define vfs_printf_nonl(...) do { PRINTF(__VA_ARGS__); } while(0) +#define vfs_puts(buf) do { PUTS(buf); } while(0) +#define vfs_putsn(buf, n) do { PUTSN(buf, n); } while(0) #else #define vfs_printf(...) do { } while(0) #define vfs_printf_nonl(...) do { } while(0) +#define vfs_puts(buf) do { } while(0) +#define vfs_putsn(buf, n) do { } while(0) #endif #define VFS_CLUSTER_SIZE 0x1000 From cdd54cc5501c5be48b6a439a765042b26a2c32c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 4 Jan 2018 00:27:31 +0100 Subject: [PATCH 3/5] read and write both working --- units/i2c/unit_i2c.c | 113 +++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 63 deletions(-) diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index d111c06..c24421e 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -231,7 +231,7 @@ static bool UI2C_init(Unit *unit) priv->dnf); LL_I2C_SetTiming(priv->periph, timing); - LL_I2C_DisableClockStretching(priv->periph); + //LL_I2C_DisableClockStretching(priv->periph); LL_I2C_Enable(priv->periph); LL_I2C_DisableOwnAddress1(priv->periph); // OA not used @@ -272,6 +272,8 @@ static void UI2C_deInit(Unit *unit) enum PinCmd_ { CMD_WRITE = 0, CMD_READ = 1, + CMD_WRITE_ADDR = 2, + CMD_READ_ADDR = 3, }; static void i2c_reset(struct priv *priv) @@ -281,8 +283,7 @@ static void i2c_reset(struct priv *priv) LL_I2C_Enable(priv->periph); } -static bool i2c_wait_until_flag(struct priv *priv, TF_ID frame_id, uint32_t flag, - bool stop_state, const char *msg) +static bool i2c_wait_until_flag(struct priv *priv, TF_ID frame_id, uint32_t flag, bool stop_state, const char *msg) { uint32_t t_start = HAL_GetTick(); while (((priv->periph->ISR & flag)!=0) != stop_state) { @@ -292,6 +293,7 @@ static bool i2c_wait_until_flag(struct priv *priv, TF_ID frame_id, uint32_t flag return false; } } + return true; } /** Handle a request message */ @@ -304,90 +306,75 @@ static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Payl uint32_t len; uint32_t t_start; + addr = pp_u16(pp); // 10-bit address has the highest bit set to 1 to indicate this + addrsize = (uint8_t) (((addr & 0x8000) == 0) ? 7 : 10); + addr &= 0x3FF; + + uint32_t ll_addrsize = (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT; + + // 7-bit address must be shifted to left for LL to use it correctly + if (addrsize == 7) addr <<= 1; + + if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_BUSY, 0, "BUSY TIMEOUT")) return false; + + uint32_t chunk_remain; + bool first; + switch (command) { case CMD_WRITE:; - addrsize = pp_u8(pp); // 7 or 10 - addr = pp_u16(pp); - - t_start = HAL_GetTick(); - while (LL_I2C_IsActiveFlag_BUSY(priv->periph)) { - if (HAL_GetTick() - t_start > 10) { - com_respond_err(frame_id, "BUSY TIMEOUT"); - i2c_reset(priv); - return false; - } - } -// if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_BUSY, 0, "BUSY TIMEOUT")) return false; + // u16 address - already read - uint32_t chunk_remain; + first = true; while (pp_length(pp) > 0) { len = pp_length(pp); - chunk_remain = (uint8_t) ((len > 255) ? 255 : len), // if more than 255, first chunk is 255 - LL_I2C_HandleTransfer(priv->periph, - (addrsize == 7) ? addr << 1 : addr, // Address must be shifted to left by one if 7-bit mode is used. Bit 0 serves for R/W flag - (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT, // translate to LL bitfields - (uint32_t) chunk_remain, + chunk_remain = (uint8_t) ((len > 255) ? 255 : len); // if more than 255, first chunk is 255 + LL_I2C_HandleTransfer(priv->periph, addr, ll_addrsize, chunk_remain, (len > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk - LL_I2C_GENERATE_START_WRITE); + first ? LL_I2C_GENERATE_START_WRITE : LL_I2C_GENERATE_NOSTARTSTOP); // no start/stop condition if we're continuing + first = false; for (; chunk_remain > 0; chunk_remain--) { - t_start = HAL_GetTick(); - while (!LL_I2C_IsActiveFlag_TXIS(priv->periph)) { - if (HAL_GetTick() - t_start > 10) { - com_respond_err(frame_id, "TXIS TIMEOUT"); - i2c_reset(priv); - return false; - } - } + if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_TXIS, 1, "TXIS TIMEOUT")) return false; uint8_t byte = pp_u8(pp); LL_I2C_TransmitData8(priv->periph, byte); } } - t_start = HAL_GetTick(); - while (!LL_I2C_IsActiveFlag_STOP(priv->periph)) { - if (HAL_GetTick() - t_start > 10) { - com_respond_err(frame_id, "STOPF TIMEOUT"); - i2c_reset(priv); - return false; - } - } + if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_STOPF, 1, "STOPF TIMEOUT")) return false; + LL_I2C_ClearFlag_STOP(priv->periph); break; case CMD_READ: - addrsize = pp_u8(pp); // 7 or 10 - addr = pp_u16(pp); + // u16 address - already read len = pp_u16(pp); - // TODO support > 255? - if (len > 256) { - com_respond_err(frame_id, "TOO LONG"); - return false; - } - - LL_I2C_HandleTransfer(priv->periph, - (addrsize == 7) ? addr << 1 : addr, - addrsize == 7 ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT, - (uint32_t) pp_length(pp), - LL_I2C_MODE_AUTOEND, // ? - LL_I2C_GENERATE_START_READ); - - for (uint32_t i = 0; i < len; i++) { - t_start = HAL_GetTick(); - while (!LL_I2C_IsActiveFlag_RXNE(priv->periph)) { - // wait for RXNE - if (HAL_GetTick() - t_start > 10) { - com_respond_err(frame_id, "RX TIMEOUT"); - return false; - } + first = true; + uint32_t n = 0; + while (len > 0) { + if (!first) { + if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_TCR, 1, "TCR TIMEOUT")) return false; } - uint8_t b = LL_I2C_ReceiveData8(priv->periph); - unit_tmp512[i] = b; + chunk_remain = (uint8_t) ((len > 255) ? 255 : len); // if more than 255, first chunk is 255 + LL_I2C_HandleTransfer(priv->periph, addr, ll_addrsize, chunk_remain, + (len > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk + first ? LL_I2C_GENERATE_START_READ : LL_I2C_GENERATE_NOSTARTSTOP); // no start/stop condition if we're continuing + first = false; + len -= chunk_remain; + + for (; chunk_remain > 0; chunk_remain--) { + if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_RXNE, 1, "RXNE TIMEOUT")) return false; + + uint8_t byte = LL_I2C_ReceiveData8(priv->periph); + unit_tmp512[n++] = byte; + } } + if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_STOPF, 1, "STOPF TIMEOUT")) return false; + LL_I2C_ClearFlag_STOP(priv->periph); + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, len); break; From 1a225d6f0612afe06a252e2f1786954854144e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 4 Jan 2018 01:20:48 +0100 Subject: [PATCH 4/5] added higher level i2c functions for working with registers --- units/i2c/unit_i2c.c | 206 +++++++++++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 64 deletions(-) diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index c24421e..424285b 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -272,8 +272,8 @@ static void UI2C_deInit(Unit *unit) enum PinCmd_ { CMD_WRITE = 0, CMD_READ = 1, - CMD_WRITE_ADDR = 2, - CMD_READ_ADDR = 3, + CMD_WRITE_REG = 2, + CMD_READ_REG = 3, }; static void i2c_reset(struct priv *priv) @@ -283,12 +283,11 @@ static void i2c_reset(struct priv *priv) LL_I2C_Enable(priv->periph); } -static bool i2c_wait_until_flag(struct priv *priv, TF_ID frame_id, uint32_t flag, bool stop_state, const char *msg) +static bool i2c_wait_until_flag(struct priv *priv, uint32_t flag, bool stop_state) { uint32_t t_start = HAL_GetTick(); while (((priv->periph->ISR & flag)!=0) != stop_state) { if (HAL_GetTick() - t_start > 10) { - com_respond_err(frame_id, msg); i2c_reset(priv); return false; } @@ -296,86 +295,165 @@ static bool i2c_wait_until_flag(struct priv *priv, TF_ID frame_id, uint32_t flag return true; } -/** Handle a request message */ -static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +static bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount) { struct priv *priv = unit->data; - uint8_t addrsize; // 7 or 10 - uint16_t addr; - uint32_t len; - uint32_t t_start; - - addr = pp_u16(pp); // 10-bit address has the highest bit set to 1 to indicate this - addrsize = (uint8_t) (((addr & 0x8000) == 0) ? 7 : 10); + uint8_t addrsize = (uint8_t) (((addr & 0x8000) == 0) ? 7 : 10); addr &= 0x3FF; - uint32_t ll_addrsize = (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT; + if (addrsize == 7) addr <<= 1; // 7-bit address must be shifted to left for LL to use it correctly + + if (!i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0)) { + dbg("BUSY TOUT"); + return false; + } + + bool first = true; + while (bcount > 0) { + uint32_t len = bcount; + uint32_t chunk_remain = (uint8_t) ((len > 255) ? 255 : len); // if more than 255, first chunk is 255 + LL_I2C_HandleTransfer(priv->periph, addr, ll_addrsize, chunk_remain, + (len > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk + first ? LL_I2C_GENERATE_START_WRITE : LL_I2C_GENERATE_NOSTARTSTOP); // no start/stop condition if we're continuing + first = false; + bcount -= chunk_remain; + + for (; chunk_remain > 0; chunk_remain--) { + if (!i2c_wait_until_flag(priv, I2C_ISR_TXIS, 1)) { + dbg("TXIS TOUT, remain %d", (int)chunk_remain); + return false; + } + uint8_t byte = *bytes++; + LL_I2C_TransmitData8(priv->periph, byte); + } + } + + if (!i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)) { + dbg("STOPF TOUT"); + return false; + } + LL_I2C_ClearFlag_STOP(priv->periph); + return true; +} - // 7-bit address must be shifted to left for LL to use it correctly - if (addrsize == 7) addr <<= 1; +static bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) +{ + struct priv *priv = unit->data; - if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_BUSY, 0, "BUSY TIMEOUT")) return false; + uint8_t addrsize = (uint8_t) (((addr & 0x8000) == 0) ? 7 : 10); + addr &= 0x3FF; + uint32_t ll_addrsize = (addrsize == 7) ? LL_I2C_ADDRSLAVE_7BIT : LL_I2C_ADDRSLAVE_10BIT; + if (addrsize == 7) addr <<= 1; // 7-bit address must be shifted to left for LL to use it correctly - uint32_t chunk_remain; - bool first; + if (!i2c_wait_until_flag(priv, I2C_ISR_BUSY, 0)) { + dbg("BUSY TOUT"); + return false; + } - switch (command) { - case CMD_WRITE:; - // u16 address - already read - - first = true; - while (pp_length(pp) > 0) { - len = pp_length(pp); - chunk_remain = (uint8_t) ((len > 255) ? 255 : len); // if more than 255, first chunk is 255 - LL_I2C_HandleTransfer(priv->periph, addr, ll_addrsize, chunk_remain, - (len > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk - first ? LL_I2C_GENERATE_START_WRITE : LL_I2C_GENERATE_NOSTARTSTOP); // no start/stop condition if we're continuing - first = false; - - for (; chunk_remain > 0; chunk_remain--) { - if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_TXIS, 1, "TXIS TIMEOUT")) return false; - - uint8_t byte = pp_u8(pp); - LL_I2C_TransmitData8(priv->periph, byte); - } + bool first = true; + uint32_t n = 0; + while (bcount > 0) { + if (!first) { + if (!i2c_wait_until_flag(priv, I2C_ISR_TCR, 1)) { + dbg("TCR TOUT"); + return false; } + } - if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_STOPF, 1, "STOPF TIMEOUT")) return false; - LL_I2C_ClearFlag_STOP(priv->periph); + uint8_t chunk_remain = (uint8_t) ((bcount > 255) ? 255 : bcount); // if more than 255, first chunk is 255 + LL_I2C_HandleTransfer(priv->periph, addr, ll_addrsize, chunk_remain, + (bcount > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk + first ? LL_I2C_GENERATE_START_READ : LL_I2C_GENERATE_NOSTARTSTOP); // no start/stop condition if we're continuing + first = false; + bcount -= chunk_remain; + + for (; chunk_remain > 0; chunk_remain--) { + if (!i2c_wait_until_flag(priv, I2C_ISR_RXNE, 1)) { + dbg("RXNE TOUT"); + return false; + } + + uint8_t byte = LL_I2C_ReceiveData8(priv->periph); + *dest++ = byte; + } + } + if (!i2c_wait_until_flag(priv, I2C_ISR_STOPF, 1)) { + dbg("STOPF TOUT"); + return false; + } + LL_I2C_ClearFlag_STOP(priv->periph); + return true; +} + +/** Handle a request message */ +static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +{ + struct priv *priv = unit->data; + + uint16_t addr; + uint32_t len; + + // 10-bit address has the highest bit set to 1 to indicate this + + uint8_t regnum; // register number + uint32_t size; // register width + + switch (command) { + case CMD_WRITE: + addr = pp_u16(pp); + const uint8_t *bb = pp_tail(pp, &len); + + if (!UU_I2C_Write(unit, addr, bb, len)) { + com_respond_err(frame_id, "TX FAIL"); + return false; + } break; case CMD_READ: - // u16 address - already read + addr = pp_u16(pp); len = pp_u16(pp); - first = true; - uint32_t n = 0; - while (len > 0) { - if (!first) { - if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_TCR, 1, "TCR TIMEOUT")) return false; - } - - chunk_remain = (uint8_t) ((len > 255) ? 255 : len); // if more than 255, first chunk is 255 - LL_I2C_HandleTransfer(priv->periph, addr, ll_addrsize, chunk_remain, - (len > 255) ? LL_I2C_MODE_RELOAD : LL_I2C_MODE_AUTOEND, // Autoend if this is the last chunk - first ? LL_I2C_GENERATE_START_READ : LL_I2C_GENERATE_NOSTARTSTOP); // no start/stop condition if we're continuing - first = false; - len -= chunk_remain; - - for (; chunk_remain > 0; chunk_remain--) { - if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_RXNE, 1, "RXNE TIMEOUT")) return false; - - uint8_t byte = LL_I2C_ReceiveData8(priv->periph); - unit_tmp512[n++] = byte; - } + if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, len)) { + com_respond_err(frame_id, "RX FAIL"); + return false; } + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, len); + break; - if (!i2c_wait_until_flag(priv, frame_id, I2C_ISR_STOPF, 1, "STOPF TIMEOUT")) return false; - LL_I2C_ClearFlag_STOP(priv->periph); + case CMD_READ_REG:; + addr = pp_u16(pp); + regnum = pp_u8(pp); // register number + size = pp_u8(pp); // total number of bytes to read (allows use of auto-increment) - com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, len); + if (!UU_I2C_Write(unit, addr, ®num, 1)) { + com_respond_err(frame_id, "REG ADDR TX FAIL"); + return false; + } + + // we read the register as if it was a unsigned integer + if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, size)) { + com_respond_err(frame_id, "REG VAL RX FAIL"); + return false; + } + // and pass it to PC to handle + com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, size); + break; + + case CMD_WRITE_REG: + addr = pp_u16(pp); + regnum = pp_u8(pp); // register number + + PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 512, NULL); + pb_u8(&pb, regnum); + const uint8_t *tail = pp_tail(pp, &size); + pb_buf(&pb, tail, size); + + if (!UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb))) { + com_respond_err(frame_id, "REG WRT FAIL"); + return false; + } break; default: From 3ed13c322faf3fd990d4f98805adbd3ca5135483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 4 Jan 2018 01:34:18 +0100 Subject: [PATCH 5/5] better API and exposed to header --- units/i2c/unit_i2c.c | 49 ++++++++++++++++++++++------------ units/i2c/unit_i2c.h | 62 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index 424285b..f68664c 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -295,7 +295,7 @@ static bool i2c_wait_until_flag(struct priv *priv, uint32_t flag, bool stop_stat return true; } -static bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount) +bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount) { struct priv *priv = unit->data; @@ -337,7 +337,7 @@ static bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32 return true; } -static bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) +bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount) { struct priv *priv = unit->data; @@ -387,6 +387,33 @@ static bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcoun return true; } +bool UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, uint32_t width) +{ + if (!UU_I2C_Write(unit, addr, ®num, 1)) { + return false; + } + + // we read the register as if it was a unsigned integer + if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, width)) { + return false; + } + + return true; +} + +bool UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *bytes, uint32_t width) +{ + PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 512, NULL); + pb_u8(&pb, regnum); + pb_buf(&pb, bytes, width); + + if (!UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb))) { + return false; + } + + return true; +} + /** Handle a request message */ static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { @@ -427,17 +454,10 @@ static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Payl regnum = pp_u8(pp); // register number size = pp_u8(pp); // total number of bytes to read (allows use of auto-increment) - if (!UU_I2C_Write(unit, addr, ®num, 1)) { - com_respond_err(frame_id, "REG ADDR TX FAIL"); - return false; - } - - // we read the register as if it was a unsigned integer - if (!UU_I2C_Read(unit, addr, (uint8_t *) unit_tmp512, size)) { - com_respond_err(frame_id, "REG VAL RX FAIL"); + if (!UU_I2C_ReadReg(unit, addr, regnum, (uint8_t *) unit_tmp512, size)) { + com_respond_err(frame_id, "READ REG FAIL"); return false; } - // and pass it to PC to handle com_respond_buf(frame_id, MSG_SUCCESS, (uint8_t *) unit_tmp512, size); break; @@ -445,13 +465,10 @@ static bool UI2C_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Payl addr = pp_u16(pp); regnum = pp_u8(pp); // register number - PayloadBuilder pb = pb_start((uint8_t*)unit_tmp512, 512, NULL); - pb_u8(&pb, regnum); const uint8_t *tail = pp_tail(pp, &size); - pb_buf(&pb, tail, size); - if (!UU_I2C_Write(unit, addr, (uint8_t *) unit_tmp512, pb_length(&pb))) { - com_respond_err(frame_id, "REG WRT FAIL"); + if (!UU_I2C_WriteReg(unit, addr, regnum, tail, size)) { + com_respond_err(frame_id, "WRITE REG FAIL"); return false; } break; diff --git a/units/i2c/unit_i2c.h b/units/i2c/unit_i2c.h index eb287a0..1301710 100644 --- a/units/i2c/unit_i2c.h +++ b/units/i2c/unit_i2c.h @@ -9,4 +9,66 @@ extern const UnitDriver UNIT_I2C; +// Unit-to-Unit API + +/** + * Raw write to I2C + * + * @param unit - I2C unit + * @param addr - device address (set highest bit if address is 10-bit) + * @param bytes - bytes to write + * @param bcount - byte count + * @return success + */ +bool UU_I2C_Write(Unit *unit, uint16_t addr, const uint8_t *bytes, uint32_t bcount); + +/** + * Raw read from I2C + * + * @param unit - I2C unit + * @param addr - device address (set highest bit if address is 10-bit) + * @param dest - buffer for read bytes + * @param bcount - byte count + * @return success + */ +bool UU_I2C_Read(Unit *unit, uint16_t addr, uint8_t *dest, uint32_t bcount); + +/** + * Read one or more registers from a I2C register-based device with auto-increment. + * + * @param unit - I2C unit + * @param addr - device address (set highest bit if address is 10-bit) + * @param regnum - first register number + * @param dest - destination buffer + * @param width - register width (or multiple consecutive registers total size) + * @return success + */ +bool UU_I2C_ReadReg(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t *dest, uint32_t width); + +/** + * Write a register value + * + * @param unit - I2C unit + * @param addr - device address (set highest bit if address is 10-bit) + * @param regnum - register number + * @param bytes - register bytes (use &byte) if just one + * @param width - register width (number of bytes) + * @return success + */ +bool UU_I2C_WriteReg(Unit *unit, uint16_t addr, uint8_t regnum, const uint8_t *bytes, uint32_t width); + +/** + * Write a 8-bit register value + * + * @param unit - I2C unit + * @param addr - device address (set highest bit if address is 10-bit) + * @param regnum - register number + * @param value - byte to write to the register + * @return success + */ +static inline bool UU_I2C_WriteReg8(Unit *unit, uint16_t addr, uint8_t regnum, uint8_t value) +{ + return UU_I2C_WriteReg(unit, addr, regnum, &value, 1); +} + #endif //GEX_F072_UNIT_I2C_H