From 82be9ecd78d7b05f0ffe056c3ee3cbc50f138641 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Sun, 25 Jun 2017 13:30:17 +0100 Subject: [PATCH] For discussion - Reconfigurable OLED display alternative --- src/main/config/parameter_group_ids.h | 3 +- src/main/drivers/bus.h | 7 + src/main/drivers/bus_i2c.h | 7 + src/main/drivers/display.h | 1 + src/main/drivers/display_ug2864hsweg01.c | 124 ++++++++-------- src/main/drivers/display_ug2864hsweg01.h | 17 ++- src/main/fc/settings.c | 5 + src/main/io/dashboard.c | 181 ++++++++++++----------- src/main/io/dashboard.h | 17 +++ src/main/io/displayport_oled.c | 16 +- src/main/io/displayport_oled.h | 2 +- 11 files changed, 215 insertions(+), 165 deletions(-) diff --git a/src/main/config/parameter_group_ids.h b/src/main/config/parameter_group_ids.h index e4b0bb3f5..889c7061d 100644 --- a/src/main/config/parameter_group_ids.h +++ b/src/main/config/parameter_group_ids.h @@ -107,7 +107,8 @@ #define PG_SONAR_CONFIG 516 #define PG_ESC_SENSOR_CONFIG 517 #define PG_I2C_CONFIG 518 -#define PG_BETAFLIGHT_END 518 +#define PG_DASHBOARD_CONFIG 519 +#define PG_BETAFLIGHT_END 519 // OSD configuration (subject to change) diff --git a/src/main/drivers/bus.h b/src/main/drivers/bus.h index 08de5e1a5..e8c143601 100644 --- a/src/main/drivers/bus.h +++ b/src/main/drivers/bus.h @@ -19,14 +19,21 @@ #include "platform.h" +#include "drivers/bus_i2c.h" #include "drivers/io_types.h" typedef union busDevice_u { struct deviceSpi_s { + SPI_TypeDef *instance; IO_t csnPin; } spi; + struct deviceI2C_s { + I2CDevice device; + uint8_t address; + } i2c; } busDevice_t; + #ifdef TARGET_BUS_INIT void targetBusInit(void); #endif diff --git a/src/main/drivers/bus_i2c.h b/src/main/drivers/bus_i2c.h index bd2712599..0f9f0c538 100644 --- a/src/main/drivers/bus_i2c.h +++ b/src/main/drivers/bus_i2c.h @@ -45,6 +45,13 @@ typedef enum I2CDevice { #define I2CDEV_COUNT 4 #endif +// Macro to convert CLI bus number to I2CDevice. +#define I2C_CFG_TO_DEV(x) ((x) - 1) + +// I2C device address range in 8-bit address mode +#define I2C_ADDR8_MIN 8 +#define I2C_ADDR8_MAX 119 + typedef struct i2cConfig_s { ioTag_t ioTagScl[I2CDEV_COUNT]; ioTag_t ioTagSda[I2CDEV_COUNT]; diff --git a/src/main/drivers/display.h b/src/main/drivers/display.h index 1cecb77ca..6caf1767d 100644 --- a/src/main/drivers/display.h +++ b/src/main/drivers/display.h @@ -20,6 +20,7 @@ struct displayPortVTable_s; typedef struct displayPort_s { const struct displayPortVTable_s *vTable; + void *device; uint8_t rows; uint8_t cols; diff --git a/src/main/drivers/display_ug2864hsweg01.c b/src/main/drivers/display_ug2864hsweg01.c index b9ac8528e..abcc402cf 100644 --- a/src/main/drivers/display_ug2864hsweg01.c +++ b/src/main/drivers/display_ug2864hsweg01.c @@ -176,78 +176,76 @@ static const uint8_t multiWiiFont[][5] = { // Refer to "Times New Roman" Font Da { 0x7A, 0x7E, 0x7E, 0x7E, 0x7A }, // (131) - 0x00C8 Vertical Bargraph - 6 (full) }; -#define OLED_address 0x3C // OLED at address 0x3C in 7bit - -static bool i2c_OLED_send_cmd(uint8_t command) +static bool i2c_OLED_send_cmd(busDevice_t *bus, uint8_t command) { - return i2cWrite(OLED_I2C_INSTANCE, OLED_address, 0x80, command); + return i2cWrite(bus->i2c.device, bus->i2c.address, 0x80, command); } -static bool i2c_OLED_send_byte(uint8_t val) +static bool i2c_OLED_send_byte(busDevice_t *bus, uint8_t val) { - return i2cWrite(OLED_I2C_INSTANCE, OLED_address, 0x40, val); + return i2cWrite(bus->i2c.device, bus->i2c.address, 0x40, val); } -void i2c_OLED_clear_display(void) +void i2c_OLED_clear_display(busDevice_t *bus) { - i2c_OLED_send_cmd(0xa6); // Set Normal Display - i2c_OLED_send_cmd(0xae); // Display OFF - i2c_OLED_send_cmd(0x20); // Set Memory Addressing Mode - i2c_OLED_send_cmd(0x00); // Set Memory Addressing Mode to Horizontal addressing mode - i2c_OLED_send_cmd(0xb0); // set page address to 0 - i2c_OLED_send_cmd(0x40); // Display start line register to 0 - i2c_OLED_send_cmd(0); // Set low col address to 0 - i2c_OLED_send_cmd(0x10); // Set high col address to 0 + i2c_OLED_send_cmd(bus, 0xa6); // Set Normal Display + i2c_OLED_send_cmd(bus, 0xae); // Display OFF + i2c_OLED_send_cmd(bus, 0x20); // Set Memory Addressing Mode + i2c_OLED_send_cmd(bus, 0x00); // Set Memory Addressing Mode to Horizontal addressing mode + i2c_OLED_send_cmd(bus, 0xb0); // set page address to 0 + i2c_OLED_send_cmd(bus, 0x40); // Display start line register to 0 + i2c_OLED_send_cmd(bus, 0); // Set low col address to 0 + i2c_OLED_send_cmd(bus, 0x10); // Set high col address to 0 for(uint16_t i = 0; i < 1024; i++) { // fill the display's RAM with graphic... 128*64 pixel picture - i2c_OLED_send_byte(0x00); // clear + i2c_OLED_send_byte(bus, 0x00); // clear } - i2c_OLED_send_cmd(0x81); // Setup CONTRAST CONTROL, following byte is the contrast Value... always a 2 byte instruction - i2c_OLED_send_cmd(200); // Here you can set the brightness 1 = dull, 255 is very bright - i2c_OLED_send_cmd(0xaf); // display on + i2c_OLED_send_cmd(bus, 0x81); // Setup CONTRAST CONTROL, following byte is the contrast Value... always a 2 byte instruction + i2c_OLED_send_cmd(bus, 200); // Here you can set the brightness 1 = dull, 255 is very bright + i2c_OLED_send_cmd(bus, 0xaf); // display on } -void i2c_OLED_clear_display_quick(void) +void i2c_OLED_clear_display_quick(busDevice_t *bus) { - i2c_OLED_send_cmd(0xb0); // set page address to 0 - i2c_OLED_send_cmd(0x40); // Display start line register to 0 - i2c_OLED_send_cmd(0); // Set low col address to 0 - i2c_OLED_send_cmd(0x10); // Set high col address to 0 + i2c_OLED_send_cmd(bus, 0xb0); // set page address to 0 + i2c_OLED_send_cmd(bus, 0x40); // Display start line register to 0 + i2c_OLED_send_cmd(bus, 0); // Set low col address to 0 + i2c_OLED_send_cmd(bus, 0x10); // Set high col address to 0 for(uint16_t i = 0; i < 1024; i++) { // fill the display's RAM with graphic... 128*64 pixel picture - i2c_OLED_send_byte(0x00); // clear + i2c_OLED_send_byte(bus, 0x00); // clear } } -void i2c_OLED_set_xy(uint8_t col, uint8_t row) +void i2c_OLED_set_xy(busDevice_t *bus, uint8_t col, uint8_t row) { - i2c_OLED_send_cmd(0xb0 + row); //set page address - i2c_OLED_send_cmd(0x00 + ((CHARACTER_WIDTH_TOTAL * col) & 0x0f)); //set low col address - i2c_OLED_send_cmd(0x10 + (((CHARACTER_WIDTH_TOTAL * col) >> 4) & 0x0f)); //set high col address + i2c_OLED_send_cmd(bus, 0xb0 + row); //set page address + i2c_OLED_send_cmd(bus, 0x00 + ((CHARACTER_WIDTH_TOTAL * col) & 0x0f)); //set low col address + i2c_OLED_send_cmd(bus, 0x10 + (((CHARACTER_WIDTH_TOTAL * col) >> 4) & 0x0f)); //set high col address } -void i2c_OLED_set_line(uint8_t row) +void i2c_OLED_set_line(busDevice_t *bus, uint8_t row) { - i2c_OLED_send_cmd(0xb0 + row); //set page address - i2c_OLED_send_cmd(0); //set low col address - i2c_OLED_send_cmd(0x10); //set high col address + i2c_OLED_send_cmd(bus, 0xb0 + row); //set page address + i2c_OLED_send_cmd(bus, 0); //set low col address + i2c_OLED_send_cmd(bus, 0x10); //set high col address } -void i2c_OLED_send_char(unsigned char ascii) +void i2c_OLED_send_char(busDevice_t *bus, unsigned char ascii) { unsigned char i; uint8_t buffer; for (i = 0; i < 5; i++) { buffer = multiWiiFont[ascii - 32][i]; buffer ^= CHAR_FORMAT; // apply - i2c_OLED_send_byte(buffer); + i2c_OLED_send_byte(bus, buffer); } - i2c_OLED_send_byte(CHAR_FORMAT); // the gap + i2c_OLED_send_byte(bus, CHAR_FORMAT); // the gap } -void i2c_OLED_send_string(const char *string) +void i2c_OLED_send_string(busDevice_t *bus, const char *string) { // Sends a string of chars until null terminator while (*string) { - i2c_OLED_send_char(*string); + i2c_OLED_send_char(bus, *string); string++; } } @@ -255,38 +253,38 @@ void i2c_OLED_send_string(const char *string) /** * according to http://www.adafruit.com/datasheets/UG-2864HSWEG01.pdf Chapter 4.4 Page 15 */ -bool ug2864hsweg01InitI2C(void) +bool ug2864hsweg01InitI2C(busDevice_t *bus) { // Set display OFF - if (!i2c_OLED_send_cmd(0xAE)) { + if (!i2c_OLED_send_cmd(bus, 0xAE)) { return false; } - i2c_OLED_send_cmd(0xD4); // Set Display Clock Divide Ratio / OSC Frequency - i2c_OLED_send_cmd(0x80); // Display Clock Divide Ratio / OSC Frequency - i2c_OLED_send_cmd(0xA8); // Set Multiplex Ratio - i2c_OLED_send_cmd(0x3F); // Multiplex Ratio for 128x64 (64-1) - i2c_OLED_send_cmd(0xD3); // Set Display Offset - i2c_OLED_send_cmd(0x00); // Display Offset - i2c_OLED_send_cmd(0x40); // Set Display Start Line - i2c_OLED_send_cmd(0x8D); // Set Charge Pump - i2c_OLED_send_cmd(0x14); // Charge Pump (0x10 External, 0x14 Internal DC/DC) - i2c_OLED_send_cmd(0xA1); // Set Segment Re-Map - i2c_OLED_send_cmd(0xC8); // Set Com Output Scan Direction - i2c_OLED_send_cmd(0xDA); // Set COM Hardware Configuration - i2c_OLED_send_cmd(0x12); // COM Hardware Configuration - i2c_OLED_send_cmd(0x81); // Set Contrast - i2c_OLED_send_cmd(0xCF); // Contrast - i2c_OLED_send_cmd(0xD9); // Set Pre-Charge Period - i2c_OLED_send_cmd(0xF1); // Set Pre-Charge Period (0x22 External, 0xF1 Internal) - i2c_OLED_send_cmd(0xDB); // Set VCOMH Deselect Level - i2c_OLED_send_cmd(0x40); // VCOMH Deselect Level - i2c_OLED_send_cmd(0xA4); // Set all pixels OFF - i2c_OLED_send_cmd(0xA6); // Set display not inverted - i2c_OLED_send_cmd(0xAF); // Set display On + i2c_OLED_send_cmd(bus, 0xD4); // Set Display Clock Divide Ratio / OSC Frequency + i2c_OLED_send_cmd(bus, 0x80); // Display Clock Divide Ratio / OSC Frequency + i2c_OLED_send_cmd(bus, 0xA8); // Set Multiplex Ratio + i2c_OLED_send_cmd(bus, 0x3F); // Multiplex Ratio for 128x64 (64-1) + i2c_OLED_send_cmd(bus, 0xD3); // Set Display Offset + i2c_OLED_send_cmd(bus, 0x00); // Display Offset + i2c_OLED_send_cmd(bus, 0x40); // Set Display Start Line + i2c_OLED_send_cmd(bus, 0x8D); // Set Charge Pump + i2c_OLED_send_cmd(bus, 0x14); // Charge Pump (0x10 External, 0x14 Internal DC/DC) + i2c_OLED_send_cmd(bus, 0xA1); // Set Segment Re-Map + i2c_OLED_send_cmd(bus, 0xC8); // Set Com Output Scan Direction + i2c_OLED_send_cmd(bus, 0xDA); // Set COM Hardware Configuration + i2c_OLED_send_cmd(bus, 0x12); // COM Hardware Configuration + i2c_OLED_send_cmd(bus, 0x81); // Set Contrast + i2c_OLED_send_cmd(bus, 0xCF); // Contrast + i2c_OLED_send_cmd(bus, 0xD9); // Set Pre-Charge Period + i2c_OLED_send_cmd(bus, 0xF1); // Set Pre-Charge Period (0x22 External, 0xF1 Internal) + i2c_OLED_send_cmd(bus, 0xDB); // Set VCOMH Deselect Level + i2c_OLED_send_cmd(bus, 0x40); // VCOMH Deselect Level + i2c_OLED_send_cmd(bus, 0xA4); // Set all pixels OFF + i2c_OLED_send_cmd(bus, 0xA6); // Set display not inverted + i2c_OLED_send_cmd(bus, 0xAF); // Set display On - i2c_OLED_clear_display(); + i2c_OLED_clear_display(bus); return true; } diff --git a/src/main/drivers/display_ug2864hsweg01.h b/src/main/drivers/display_ug2864hsweg01.h index 3a51eab7a..6d31ebf7a 100644 --- a/src/main/drivers/display_ug2864hsweg01.h +++ b/src/main/drivers/display_ug2864hsweg01.h @@ -17,6 +17,8 @@ #pragma once +#include "drivers/bus.h" + #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 @@ -34,12 +36,11 @@ #define VERTICAL_BARGRAPH_ZERO_CHARACTER (128 + 32) #define VERTICAL_BARGRAPH_CHARACTER_COUNT 7 -bool ug2864hsweg01InitI2C(void); - -void i2c_OLED_set_xy(uint8_t col, uint8_t row); -void i2c_OLED_set_line(uint8_t row); -void i2c_OLED_send_char(unsigned char ascii); -void i2c_OLED_send_string(const char *string); -void i2c_OLED_clear_display(void); -void i2c_OLED_clear_display_quick(void); +bool ug2864hsweg01InitI2C(busDevice_t *bus); +void i2c_OLED_set_xy(busDevice_t *bus, uint8_t col, uint8_t row); +void i2c_OLED_set_line(busDevice_t *bus, uint8_t row); +void i2c_OLED_send_char(busDevice_t *bus, unsigned char ascii); +void i2c_OLED_send_string(busDevice_t *bus, const char *string); +void i2c_OLED_clear_display(busDevice_t *bus); +void i2c_OLED_clear_display_quick(busDevice_t *bus); diff --git a/src/main/fc/settings.c b/src/main/fc/settings.c index 32791c76c..e29d9ff5e 100644 --- a/src/main/fc/settings.c +++ b/src/main/fc/settings.c @@ -53,6 +53,7 @@ #include "flight/pid.h" #include "flight/servos.h" +#include "io/dashboard.h" #include "io/gimbal.h" #include "io/gps.h" #include "io/ledstrip.h" @@ -720,6 +721,10 @@ const clivalue_t valueTable[] = { { "esc_sensor_halfduplex", VAR_UINT8 | MASTER_VALUE | MODE_LOOKUP, .config.lookup = { TABLE_OFF_ON }, PG_ESC_SENSOR_CONFIG, offsetof(escSensorConfig_t, halfDuplex) }, #endif { "led_inversion", VAR_UINT8 | MASTER_VALUE, .config.minmax = { 0, ((1 << STATUS_LED_NUMBER) - 1) }, PG_STATUS_LED_CONFIG, offsetof(statusLedConfig_t, inversion) }, +#ifdef USE_DASHBOARD + { "dashboard_i2c_bus", VAR_UINT8 | MASTER_VALUE, .config.minmax = { 0, I2CDEV_COUNT }, PG_DASHBOARD_CONFIG, offsetof(dashboardConfig_t, device) }, + { "dashboard_i2c_addr", VAR_UINT8 | MASTER_VALUE, .config.minmax = { I2C_ADDR8_MIN, I2C_ADDR8_MAX }, PG_DASHBOARD_CONFIG, offsetof(dashboardConfig_t, address) }, +#endif }; const uint16_t valueTableEntryCount = ARRAYLEN(valueTable); diff --git a/src/main/io/dashboard.c b/src/main/io/dashboard.c index f54511fb5..a954abb9d 100644 --- a/src/main/io/dashboard.c +++ b/src/main/io/dashboard.c @@ -31,6 +31,7 @@ #include "build/build_config.h" +#include "drivers/bus.h" #include "drivers/display.h" #include "drivers/display_ug2864hsweg01.h" #include "drivers/time.h" @@ -71,11 +72,20 @@ #include "sensors/sensors.h" +PG_REGISTER_WITH_RESET_TEMPLATE(dashboardConfig_t, dashboardConfig, PG_DASHBOARD_CONFIG, 0); + +PG_RESET_TEMPLATE(dashboardConfig_t, dashboardConfig, + .device = DASHBOARD_I2C_INSTANCE, + .address = DASHBOARD_I2C_ADDRESS, +); + #define MICROSECONDS_IN_A_SECOND (1000 * 1000) #define DISPLAY_UPDATE_FREQUENCY (MICROSECONDS_IN_A_SECOND / 5) #define PAGE_CYCLE_FREQUENCY (MICROSECONDS_IN_A_SECOND * 5) +static busDevice_t bus; + static uint32_t nextDisplayUpdateAt = 0; static bool dashboardPresent = false; @@ -119,12 +129,14 @@ typedef struct pageState_s { static pageState_t pageState; -void resetDisplay(void) { - dashboardPresent = ug2864hsweg01InitI2C(); +void resetDisplay(void) +{ + dashboardPresent = ug2864hsweg01InitI2C(&bus); } -void LCDprint(uint8_t i) { - i2c_OLED_send_char(i); +void LCDprint(uint8_t i) +{ + i2c_OLED_send_char(&bus, i); } void padLineBuffer(void) @@ -170,8 +182,8 @@ void fillScreenWithCharacters() { for (uint8_t row = 0; row < SCREEN_CHARACTER_ROW_COUNT; row++) { for (uint8_t column = 0; column < SCREEN_CHARACTER_COLUMN_COUNT; column++) { - i2c_OLED_set_xy(column, row); - i2c_OLED_send_char('A' + column); + i2c_OLED_set_xy(&bus, column, row); + i2c_OLED_send_char(&bus, 'A' + column); } } } @@ -181,22 +193,22 @@ void fillScreenWithCharacters() void updateTicker(void) { static uint8_t tickerIndex = 0; - i2c_OLED_set_xy(SCREEN_CHARACTER_COLUMN_COUNT - 1, 0); - i2c_OLED_send_char(tickerCharacters[tickerIndex]); + i2c_OLED_set_xy(&bus, SCREEN_CHARACTER_COLUMN_COUNT - 1, 0); + i2c_OLED_send_char(&bus, tickerCharacters[tickerIndex]); tickerIndex++; tickerIndex = tickerIndex % TICKER_CHARACTER_COUNT; } void updateRxStatus(void) { - i2c_OLED_set_xy(SCREEN_CHARACTER_COLUMN_COUNT - 2, 0); + i2c_OLED_set_xy(&bus, SCREEN_CHARACTER_COLUMN_COUNT - 2, 0); char rxStatus = '!'; if (rxIsReceivingSignal()) { rxStatus = 'r'; } if (rxAreFlightChannelsValid()) { rxStatus = 'R'; } - i2c_OLED_send_char(rxStatus); + i2c_OLED_send_char(&bus, rxStatus); } void updateFailsafeStatus(void) @@ -222,19 +234,19 @@ void updateFailsafeStatus(void) failsafeIndicator = 'r'; break; } - i2c_OLED_set_xy(SCREEN_CHARACTER_COLUMN_COUNT - 3, 0); - i2c_OLED_send_char(failsafeIndicator); + i2c_OLED_set_xy(&bus, SCREEN_CHARACTER_COLUMN_COUNT - 3, 0); + i2c_OLED_send_char(&bus, failsafeIndicator); } void showTitle() { - i2c_OLED_set_line(0); - i2c_OLED_send_string(pageState.page->title); + i2c_OLED_set_line(&bus, 0); + i2c_OLED_send_string(&bus, pageState.page->title); } void handlePageChange(void) { - i2c_OLED_clear_display_quick(); + i2c_OLED_clear_display_quick(&bus); showTitle(); } @@ -253,7 +265,7 @@ void showRxPage(void) { for (uint8_t channelIndex = 0; channelIndex < rxRuntimeConfig.channelCount && channelIndex < RX_CHANNELS_PER_PAGE_COUNT; channelIndex += 2) { - i2c_OLED_set_line((channelIndex / 2) + PAGE_TITLE_LINE_COUNT); + i2c_OLED_set_line(&bus, (channelIndex / 2) + PAGE_TITLE_LINE_COUNT); drawRxChannel(channelIndex, HALF_SCREEN_CHARACTER_COLUMN_COUNT); @@ -274,11 +286,11 @@ void showWelcomePage(void) uint8_t rowIndex = PAGE_TITLE_LINE_COUNT; tfp_sprintf(lineBuffer, "v%s (%s)", FC_VERSION_STRING, shortGitRevision); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(targetName); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, targetName); } void showArmedPage(void) @@ -290,8 +302,8 @@ void showProfilePage(void) uint8_t rowIndex = PAGE_TITLE_LINE_COUNT; tfp_sprintf(lineBuffer, "Profile: %d", getCurrentPidProfileIndex()); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); static const char* const axisTitles[3] = {"ROL", "PIT", "YAW"}; const pidProfile_t *pidProfile = currentPidProfile; @@ -303,14 +315,14 @@ void showProfilePage(void) pidProfile->pid[axis].D ); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); } const uint8_t currentRateProfileIndex = getCurrentControlRateProfileIndex(); tfp_sprintf(lineBuffer, "Rate profile: %d", currentRateProfileIndex); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); const controlRateConfig_t *controlRateConfig = controlRateProfiles(currentRateProfileIndex); tfp_sprintf(lineBuffer, "RCE: %d, RCR: %d", @@ -318,8 +330,8 @@ void showProfilePage(void) controlRateConfig->rcRate8 ); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "RR:%d PR:%d YR:%d", controlRateConfig->rates[FD_ROLL], @@ -327,8 +339,8 @@ void showProfilePage(void) controlRateConfig->rates[FD_YAW] ); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); } #define SATELLITE_COUNT (sizeof(GPS_svinfo_cno) / sizeof(GPS_svinfo_cno[0])) #define SATELLITE_GRAPH_LEFT_OFFSET ((SCREEN_CHARACTER_COLUMN_COUNT - SATELLITE_COUNT) / 2) @@ -351,77 +363,77 @@ void showGpsPage() { gpsTicker = gpsTicker % TICKER_CHARACTER_COUNT; } - i2c_OLED_set_xy(0, rowIndex); - i2c_OLED_send_char(tickerCharacters[gpsTicker]); + i2c_OLED_set_xy(&bus, 0, rowIndex); + i2c_OLED_send_char(&bus, tickerCharacters[gpsTicker]); - i2c_OLED_set_xy(MAX(0, SATELLITE_GRAPH_LEFT_OFFSET), rowIndex++); + i2c_OLED_set_xy(&bus, MAX(0, SATELLITE_GRAPH_LEFT_OFFSET), rowIndex++); uint32_t index; for (index = 0; index < SATELLITE_COUNT && index < SCREEN_CHARACTER_COLUMN_COUNT; index++) { uint8_t bargraphOffset = ((uint16_t) GPS_svinfo_cno[index] * VERTICAL_BARGRAPH_CHARACTER_COUNT) / (GPS_DBHZ_MAX - 1); bargraphOffset = MIN(bargraphOffset, VERTICAL_BARGRAPH_CHARACTER_COUNT - 1); - i2c_OLED_send_char(VERTICAL_BARGRAPH_ZERO_CHARACTER + bargraphOffset); + i2c_OLED_send_char(&bus, VERTICAL_BARGRAPH_ZERO_CHARACTER + bargraphOffset); } char fixChar = STATE(GPS_FIX) ? 'Y' : 'N'; tfp_sprintf(lineBuffer, "Sats: %d Fix: %c", gpsSol.numSat, fixChar); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "La/Lo: %d/%d", gpsSol.llh.lat / GPS_DEGREES_DIVIDER, gpsSol.llh.lon / GPS_DEGREES_DIVIDER); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "Spd: %d", gpsSol.groundSpeed); padHalfLineBuffer(); - i2c_OLED_set_line(rowIndex); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "GC: %d", gpsSol.groundCourse); padHalfLineBuffer(); - i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_xy(&bus, HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "RX: %d", GPS_packetCount); padHalfLineBuffer(); - i2c_OLED_set_line(rowIndex); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "ERRs: %d", gpsData.errors, gpsData.timeouts); padHalfLineBuffer(); - i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_xy(&bus, HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "Dt: %d", gpsData.lastMessage - gpsData.lastLastMessage); padHalfLineBuffer(); - i2c_OLED_set_line(rowIndex); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex); + i2c_OLED_send_string(&bus, lineBuffer); tfp_sprintf(lineBuffer, "TOs: %d", gpsData.timeouts); padHalfLineBuffer(); - i2c_OLED_set_xy(HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_xy(&bus, HALF_SCREEN_CHARACTER_COLUMN_COUNT, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); strncpy(lineBuffer, gpsPacketLog, GPS_PACKET_LOG_ENTRY_COUNT); padHalfLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); #ifdef GPS_PH_DEBUG tfp_sprintf(lineBuffer, "Angles: P:%d R:%d", GPS_angle[PITCH], GPS_angle[ROLL]); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); #endif #if 0 tfp_sprintf(lineBuffer, "%d %d %d %d", debug[0], debug[1], debug[2], debug[3]); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); #endif } #endif @@ -433,11 +445,11 @@ void showBatteryPage(void) if (batteryConfig()->voltageMeterSource != VOLTAGE_METER_NONE) { tfp_sprintf(lineBuffer, "Volts: %d.%1d Cells: %d", getBatteryVoltage() / 10, getBatteryVoltage() % 10, getBatteryCellCount()); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); uint8_t batteryPercentage = calculateBatteryPercentageRemaining(); - i2c_OLED_set_line(rowIndex++); + i2c_OLED_set_line(&bus, rowIndex++); drawHorizonalPercentageBar(SCREEN_CHARACTER_COLUMN_COUNT, batteryPercentage); } @@ -446,11 +458,11 @@ void showBatteryPage(void) int32_t amperage = getAmperage(); tfp_sprintf(lineBuffer, "Amps: %d.%2d mAh: %d", amperage / 100, amperage % 100, getMAhDrawn()); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); uint8_t capacityPercentage = calculateBatteryPercentageRemaining(); - i2c_OLED_set_line(rowIndex++); + i2c_OLED_set_line(&bus, rowIndex++); drawHorizonalPercentageBar(SCREEN_CHARACTER_COLUMN_COUNT, capacityPercentage); } } @@ -460,36 +472,36 @@ void showSensorsPage(void) uint8_t rowIndex = PAGE_TITLE_LINE_COUNT; static const char *format = "%s %5d %5d %5d"; - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(" X Y Z"); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, " X Y Z"); if (sensors(SENSOR_ACC)) { tfp_sprintf(lineBuffer, format, "ACC", acc.accSmooth[X], acc.accSmooth[Y], acc.accSmooth[Z]); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); } if (sensors(SENSOR_GYRO)) { tfp_sprintf(lineBuffer, format, "GYR", lrintf(gyro.gyroADCf[X]), lrintf(gyro.gyroADCf[Y]), lrintf(gyro.gyroADCf[Z])); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); } #ifdef MAG if (sensors(SENSOR_MAG)) { tfp_sprintf(lineBuffer, format, "MAG", mag.magADC[X], mag.magADC[Y], mag.magADC[Z]); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); } #endif tfp_sprintf(lineBuffer, format, "I&H", attitude.values.roll, attitude.values.pitch, DECIDEGREES_TO_DEGREES(attitude.values.yaw)); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); /* uint8_t length; @@ -502,8 +514,8 @@ void showSensorsPage(void) } ftoa(EstG.A[Y], lineBuffer + length); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); ftoa(EstG.A[Z], lineBuffer); length = strlen(lineBuffer); @@ -513,8 +525,8 @@ void showSensorsPage(void) } ftoa(smallAngle, lineBuffer + length); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); */ } @@ -525,8 +537,8 @@ void showTasksPage(void) uint8_t rowIndex = PAGE_TITLE_LINE_COUNT; static const char *format = "%2d%6d%5d%4d%4d"; - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string("Task max avg mx% av%"); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, "Task max avg mx% av%"); cfTaskInfo_t taskInfo; for (cfTaskId_e taskId = 0; taskId < TASK_COUNT; ++taskId) { getTaskInfo(taskId, &taskInfo); @@ -536,8 +548,8 @@ void showTasksPage(void) const int averageLoad = (taskInfo.averageExecutionTime * taskFrequency + 5000) / 10000; tfp_sprintf(lineBuffer, format, taskId, taskInfo.maxExecutionTime, taskInfo.averageExecutionTime, maxLoad, averageLoad); padLineBuffer(); - i2c_OLED_set_line(rowIndex++); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex++); + i2c_OLED_send_string(&bus, lineBuffer); if (rowIndex > SCREEN_CHARACTER_ROW_COUNT) { break; } @@ -553,8 +565,8 @@ void showDebugPage(void) for (int rowIndex = 0; rowIndex < 4; rowIndex++) { tfp_sprintf(lineBuffer, "%d = %5d", rowIndex, debug[rowIndex]); padLineBuffer(); - i2c_OLED_set_line(rowIndex + PAGE_TITLE_LINE_COUNT); - i2c_OLED_send_string(lineBuffer); + i2c_OLED_set_line(&bus, rowIndex + PAGE_TITLE_LINE_COUNT); + i2c_OLED_send_string(&bus, lineBuffer); } } #endif @@ -664,11 +676,14 @@ void dashboardUpdate(timeUs_t currentTimeUs) void dashboardInit(void) { + bus.i2c.device = I2C_CFG_TO_DEV(dashboardConfig()->device); + bus.i2c.address = dashboardConfig()->address; + delay(200); resetDisplay(); delay(200); - displayPort = displayPortOledInit(); + displayPort = displayPortOledInit(&bus); #if defined(CMS) if (dashboardPresent) { cmsDisplayPortRegister(displayPort); diff --git a/src/main/io/dashboard.h b/src/main/io/dashboard.h index e7cc81f1f..10339369e 100644 --- a/src/main/io/dashboard.h +++ b/src/main/io/dashboard.h @@ -16,9 +16,26 @@ */ #include "common/time.h" +#include "config/parameter_group.h" +#include "drivers/bus_i2c.h" #define ENABLE_DEBUG_DASHBOARD_PAGE +#ifdef OLED_I2C_INSTANCE +#define DASHBOARD_I2C_INSTANCE OLED_I2C_INSTANCE +#else +#define DASHBOARD_I2C_INSTANCE I2CDEV_1 +#endif + +#define DASHBOARD_I2C_ADDRESS 0x3C // OLED at address 0x3C in 7bit + +typedef struct dashboardConfig_s { + I2CDevice device; + uint8_t address; +} dashboardConfig_t; + +PG_DECLARE(dashboardConfig_t, dashboardConfig); + typedef enum { PAGE_WELCOME, PAGE_ARMED, diff --git a/src/main/io/displayport_oled.c b/src/main/io/displayport_oled.c index fc60fed25..09b8f6aa8 100644 --- a/src/main/io/displayport_oled.c +++ b/src/main/io/displayport_oled.c @@ -41,8 +41,7 @@ static int oledRelease(displayPort_t *displayPort) static int oledClearScreen(displayPort_t *displayPort) { - UNUSED(displayPort); - i2c_OLED_clear_display_quick(); + i2c_OLED_clear_display_quick(displayPort->device); return 0; } @@ -59,17 +58,15 @@ static int oledScreenSize(const displayPort_t *displayPort) static int oledWrite(displayPort_t *displayPort, uint8_t x, uint8_t y, const char *s) { - UNUSED(displayPort); - i2c_OLED_set_xy(x, y); - i2c_OLED_send_string(s); + i2c_OLED_set_xy(displayPort->device, x, y); + i2c_OLED_send_string(displayPort->device, s); return 0; } static int oledWriteChar(displayPort_t *displayPort, uint8_t x, uint8_t y, uint8_t c) { - UNUSED(displayPort); - i2c_OLED_set_xy(x, y); - i2c_OLED_send_char(c); + i2c_OLED_set_xy(displayPort->device, x, y); + i2c_OLED_send_char(displayPort->device, c); return 0; } @@ -110,8 +107,9 @@ static const displayPortVTable_t oledVTable = { .txBytesFree = oledTxBytesFree }; -displayPort_t *displayPortOledInit(void) +displayPort_t *displayPortOledInit(void *device) { + oledDisplayPort.device = device; displayInit(&oledDisplayPort, &oledVTable); oledDisplayPort.rows = SCREEN_CHARACTER_ROW_COUNT; oledDisplayPort.cols = SCREEN_CHARACTER_COLUMN_COUNT; diff --git a/src/main/io/displayport_oled.h b/src/main/io/displayport_oled.h index 4daa6de1c..469b79aeb 100644 --- a/src/main/io/displayport_oled.h +++ b/src/main/io/displayport_oled.h @@ -17,4 +17,4 @@ #pragma once -displayPort_t *displayPortOledInit(void); +displayPort_t *displayPortOledInit(void *device);