From feaa43f37c01cf832fed17572d915e5709231893 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sat, 8 Jun 2024 19:20:49 +0200 Subject: WIP raspberry pi pico pbdrv --- lib/pbdrv/drv/rp2040/cfg.cmake | 7 ++++++ lib/pbdrv/drv/rp2040/mod.c | 50 ++++++++++++++++++++++++++++++++++++++++++ lib/pbdrv/drv/rp2040/mod.h | 13 +++++++++++ 3 files changed, 70 insertions(+) create mode 100644 lib/pbdrv/drv/rp2040/cfg.cmake create mode 100644 lib/pbdrv/drv/rp2040/mod.c create mode 100644 lib/pbdrv/drv/rp2040/mod.h (limited to 'lib/pbdrv/drv/rp2040') diff --git a/lib/pbdrv/drv/rp2040/cfg.cmake b/lib/pbdrv/drv/rp2040/cfg.cmake new file mode 100644 index 0000000..0fbad18 --- /dev/null +++ b/lib/pbdrv/drv/rp2040/cfg.cmake @@ -0,0 +1,7 @@ +if(NOT PICO_PLATFORM STREQUAL "rp2040") + return() +endif() + +target_sources(pbdrv-mod PRIVATE "${CMAKE_CURRENT_LIST_DIR}/mod.c") +target_link_libraries(pbdrv-mod hardware_i2c pico_i2c_slave) + diff --git a/lib/pbdrv/drv/rp2040/mod.c b/lib/pbdrv/drv/rp2040/mod.c new file mode 100644 index 0000000..26882f7 --- /dev/null +++ b/lib/pbdrv/drv/rp2040/mod.c @@ -0,0 +1,50 @@ +#include "mod.h" + +#include "../../pb.h" +#include "../../pb-types.h" +#include "../../pb-mod.h" + +#include +#include +#include + +#define PBDRV_I2C i2c0 +#define BUF_SIZE 256 + +// NOTE: this function is called from the I2C ISR, and should return as quickly +// as possible. +static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { + uint8_t data[BUF_SIZE]; + size_t size = 0; + // pbdrv_i2c_recv(NULL, 0); + + switch (event) { + case I2C_SLAVE_RECEIVE: { + if (size == BUF_SIZE) return; + data[size++] = i2c_read_byte_raw(PBDRV_I2C); + break; + } + case I2C_SLAVE_FINISH: { + // TODO: handle this w/ queue mechanism instead? + pbdrv_i2c_recv(data, size); + size = 0; + break; + } + default: break; + } +} + +void pbdrv_setup() { + i2c_init(PBDRV_I2C, PB_CLOCK_SPEED_HZ); + i2c_slave_init(PBDRV_I2C, PBDRV_MOD_ADDR, &recv_event); +} + +__weak void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { + i2c_set_slave_mode(PBDRV_I2C, false, PBDRV_MOD_ADDR); + + // false to write stop condition to i2c bus + i2c_write_timeout_us(PBDRV_I2C, addr, buf, sz, false, PB_TIMEOUT_US); + + i2c_set_slave_mode(PBDRV_I2C, true, PBDRV_MOD_ADDR); +} + diff --git a/lib/pbdrv/drv/rp2040/mod.h b/lib/pbdrv/drv/rp2040/mod.h new file mode 100644 index 0000000..0cf2e63 --- /dev/null +++ b/lib/pbdrv/drv/rp2040/mod.h @@ -0,0 +1,13 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +//! puzzle bus driver setup +void pbdrv_setup(); + +#ifdef __cplusplus +} +#endif + -- cgit v1.2.3 From 4bdabb2dbf8d523e71f22f994070e99f349c2113 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sun, 9 Jun 2024 17:01:58 +0200 Subject: rp2040 driver send still working (kinda) --- lib/pbdrv/drv/rp2040/mod.c | 23 ++++++++++++++++++----- main/i2c.c | 42 +++++++++++++++++++++--------------------- main/init.c | 3 --- 3 files changed, 39 insertions(+), 29 deletions(-) (limited to 'lib/pbdrv/drv/rp2040') diff --git a/lib/pbdrv/drv/rp2040/mod.c b/lib/pbdrv/drv/rp2040/mod.c index 26882f7..b572c4e 100644 --- a/lib/pbdrv/drv/rp2040/mod.c +++ b/lib/pbdrv/drv/rp2040/mod.c @@ -11,12 +11,13 @@ #define PBDRV_I2C i2c0 #define BUF_SIZE 256 -// NOTE: this function is called from the I2C ISR, and should return as quickly -// as possible. +/** + * \note this function is called from the I2C ISR, and should return as quickly + * as possible. + */ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { - uint8_t data[BUF_SIZE]; - size_t size = 0; - // pbdrv_i2c_recv(NULL, 0); + static uint8_t data[BUF_SIZE]; + static size_t size = 0; switch (event) { case I2C_SLAVE_RECEIVE: { @@ -39,6 +40,18 @@ void pbdrv_setup() { i2c_slave_init(PBDRV_I2C, PBDRV_MOD_ADDR, &recv_event); } +/** + * While the RP2040's datasheet claims it supports multi-master configurations + * by implementing bus arbitration, it does not natively support a mode where + * it is configured as a (multi-)master with a slave address, such that it can + * be addressed by other multi-masters. This function includes a hacky + * workaround that teporarily sets the RP2040 to I2C master mode to send a + * message, and then restores it back to slave mode. + * + * This approach results in some received frames being (partially) dropped in + * the time period between the invocation of this function and the bus becoming + * idle (and the message is sent). + */ __weak void pbdrv_i2c_send(i2c_addr_t addr, const uint8_t * buf, size_t sz) { i2c_set_slave_mode(PBDRV_I2C, false, PBDRV_MOD_ADDR); diff --git a/main/i2c.c b/main/i2c.c index 5db5b61..d92a93b 100644 --- a/main/i2c.c +++ b/main/i2c.c @@ -9,26 +9,26 @@ #include "i2c.h" #include "pb-mod.h" -uint8_t* scan_bus(uint8_t *array) { - int ret; - int i = 0; - uint8_t rxdata; - - for(int addr = 0; addr < (1<<7); addr++) { - // ignore reserved addresses - // These are any addresses of the form 000 0xxx or 111 1xxx - // ret = i2c_read_blocking(I2C_PORT, addr, &rxdata, 1, false); - - // if acknowledged -> ret == number of bytes sent - if(ret > 0){ - printf("found i2c slave on addr: %d\n", addr); - array[i] = addr; - i++; - } - } - - return array; -} +// uint8_t* scan_bus(uint8_t *array) { +// int ret; +// int i = 0; +// uint8_t rxdata; +// +// for(int addr = 0; addr < (1<<7); addr++) { +// // ignore reserved addresses +// // These are any addresses of the form 000 0xxx or 111 1xxx +// // ret = i2c_read_blocking(I2C_PORT, addr, &rxdata, 1, false); +// +// // if acknowledged -> ret == number of bytes sent +// if(ret > 0){ +// printf("found i2c slave on addr: %d\n", addr); +// array[i] = addr; +// i++; +// } +// } +// +// return array; +// } void bus_task() { // scan bus for slaves @@ -40,7 +40,7 @@ void bus_task() { // init_addr_array(found, MAX_SLAVES); while (true) { - vTaskDelay(9 / portTICK_PERIOD_MS); + vTaskDelay(10 / portTICK_PERIOD_MS); pbdrv_i2c_send(0x69, (uint8_t *) "bbbbbbbb", 9); // i2c_write_blocking(i2c0, 0x69, (uint8_t *) "bbbbbbbb", 9, false); diff --git a/main/init.c b/main/init.c index 1cfec9a..bd00c04 100644 --- a/main/init.c +++ b/main/init.c @@ -25,8 +25,6 @@ static void init_wifi() { if (cyw43_arch_wifi_connect_timeout_ms(CFG_NET_SSID, CFG_NET_PASS, CFG_NET_AUTH, CFG_NET_CONN_TIMEOUT)) panic("cyw43_arch_wifi_connect failed\n"); - printf("connected to Wi-Fi\n"); - // TODO: announce hostname(?) } @@ -35,7 +33,6 @@ static void init_i2c() { gpio_set_function(CFG_SCL_PIN, GPIO_FUNC_I2C); pbdrv_setup(); - //printf("i2c setup\n"); } static void async_init() { -- cgit v1.2.3 From a3ecfc2a6e6ace7bcb7666afc37ff97f9ce401b4 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Sun, 9 Jun 2024 17:37:44 +0200 Subject: WIP rp2040 pbdrv recv outside irq handler --- lib/pbdrv/drv/rp2040/mod.c | 16 +++++++++++++--- main/i2c.c | 7 ++++--- 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'lib/pbdrv/drv/rp2040') diff --git a/lib/pbdrv/drv/rp2040/mod.c b/lib/pbdrv/drv/rp2040/mod.c index b572c4e..6becdee 100644 --- a/lib/pbdrv/drv/rp2040/mod.c +++ b/lib/pbdrv/drv/rp2040/mod.c @@ -11,13 +11,22 @@ #define PBDRV_I2C i2c0 #define BUF_SIZE 256 +static volatile bool pbdrv_i2c_msg_avail = false; +static uint8_t data[BUF_SIZE]; +static size_t size = 0; + +// TODO: create event group instead of pbdrv_i2c_msg_avail +// TODO: create freertos task that monitors the pbdrv_i2c_msg_avail flag and +// calls pbdrv_i2c_recv when a message is received + + /** * \note this function is called from the I2C ISR, and should return as quickly * as possible. */ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { - static uint8_t data[BUF_SIZE]; - static size_t size = 0; + // message needs to be handled first + if (pbdrv_i2c_msg_avail) return; switch (event) { case I2C_SLAVE_RECEIVE: { @@ -27,7 +36,8 @@ static void recv_event(i2c_inst_t *i2c, i2c_slave_event_t event) { } case I2C_SLAVE_FINISH: { // TODO: handle this w/ queue mechanism instead? - pbdrv_i2c_recv(data, size); + // pbdrv_i2c_recv(data, size); + pbdrv_i2c_msg_avail = true; size = 0; break; } diff --git a/main/i2c.c b/main/i2c.c index d92a93b..8edb1e8 100644 --- a/main/i2c.c +++ b/main/i2c.c @@ -30,6 +30,10 @@ // return array; // } +void pbdrv_i2c_recv(const uint8_t * a, size_t b) { + printf("%.*s", b, a); +} + void bus_task() { // scan bus for slaves // send updates at regular intervals @@ -42,9 +46,6 @@ void bus_task() { while (true) { vTaskDelay(10 / portTICK_PERIOD_MS); pbdrv_i2c_send(0x69, (uint8_t *) "bbbbbbbb", 9); - - // i2c_write_blocking(i2c0, 0x69, (uint8_t *) "bbbbbbbb", 9, false); - // pbdrv_i2c_recv(NULL, 0); } // while(1) { -- cgit v1.2.3