diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index b6ce209..ee59443 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -26,4 +26,4 @@ } ], "version": 4 -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 7e80fdb..d2133bd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,7 @@ "interface/ftdi/esp32_devkitj_v1.cfg", "target/esp32s3.cfg" ], - "idf.port": "/dev/cu.usbserial-1464301", + "idf.port": "/dev/cu.usbserial-1464401", "idf.pythonBinPath": "/Users/skot/.espressif/python_env/idf4.4_py3.9_env/bin/python", "idf.toolsPath": "/Users/skot/.espressif", "files.associations": { @@ -16,7 +16,9 @@ "string": "c", "string_view": "c", "ds4432u.h": "c", - "led_controller.h": "c" + "led_controller.h": "c", + "*.tcc": "c", + "*.ipp": "c" }, "idf.flashType": "UART" } diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 49a62d1..dcfa4be 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "adc.c" "INA260.c" "EMC2101.c" "i2c_simple_main.c" "led_controller.c" "DS4432U.c" "EMC2101.c" "INA260.c" "adc.c" +idf_component_register(SRCS "adc.c" "INA260.c" "EMC2101.c" "i2c_simple_main.c" "led_controller.c" "DS4432U.c" "EMC2101.c" "INA260.c" "adc.c" "oled.c" "fonts.c" INCLUDE_DIRS ".") diff --git a/main/fonts.c b/main/fonts.c new file mode 100644 index 0000000..9480893 --- /dev/null +++ b/main/fonts.c @@ -0,0 +1,50 @@ + +// 5x7 font (in 6x8 cell) +unsigned char ucSmallFont[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x45,0x51,0x45,0x3e,0x00,0x3e,0x6b,0x6f, + 0x6b,0x3e,0x00,0x1c,0x3e,0x7c,0x3e,0x1c,0x00,0x18,0x3c,0x7e,0x3c,0x18,0x00,0x30, + 0x36,0x7f,0x36,0x30,0x00,0x18,0x5c,0x7e,0x5c,0x18,0x00,0x00,0x18,0x18,0x00,0x00, + 0x00,0xff,0xe7,0xe7,0xff,0xff,0x00,0x3c,0x24,0x24,0x3c,0x00,0x00,0xc3,0xdb,0xdb, + 0xc3,0xff,0x00,0x30,0x48,0x4a,0x36,0x0e,0x00,0x06,0x29,0x79,0x29,0x06,0x00,0x60, + 0x70,0x3f,0x02,0x04,0x00,0x60,0x7e,0x0a,0x35,0x3f,0x00,0x2a,0x1c,0x36,0x1c,0x2a, + 0x00,0x00,0x7f,0x3e,0x1c,0x08,0x00,0x08,0x1c,0x3e,0x7f,0x00,0x00,0x14,0x36,0x7f, + 0x36,0x14,0x00,0x00,0x5f,0x00,0x5f,0x00,0x00,0x06,0x09,0x7f,0x01,0x7f,0x00,0x22, + 0x4d,0x55,0x59,0x22,0x00,0x60,0x60,0x60,0x60,0x00,0x00,0x14,0xb6,0xff,0xb6,0x14, + 0x00,0x04,0x06,0x7f,0x06,0x04,0x00,0x10,0x30,0x7f,0x30,0x10,0x00,0x08,0x08,0x3e, + 0x1c,0x08,0x00,0x08,0x1c,0x3e,0x08,0x08,0x00,0x78,0x40,0x40,0x40,0x40,0x00,0x08, + 0x3e,0x08,0x3e,0x08,0x00,0x30,0x3c,0x3f,0x3c,0x30,0x00,0x03,0x0f,0x3f,0x0f,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x5f,0x06,0x00,0x00,0x07,0x03,0x00, + 0x07,0x03,0x00,0x24,0x7e,0x24,0x7e,0x24,0x00,0x24,0x2b,0x6a,0x12,0x00,0x00,0x63, + 0x13,0x08,0x64,0x63,0x00,0x36,0x49,0x56,0x20,0x50,0x00,0x00,0x07,0x03,0x00,0x00, + 0x00,0x00,0x3e,0x41,0x00,0x00,0x00,0x00,0x41,0x3e,0x00,0x00,0x00,0x08,0x3e,0x1c, + 0x3e,0x08,0x00,0x08,0x08,0x3e,0x08,0x08,0x00,0x00,0xe0,0x60,0x00,0x00,0x00,0x08, + 0x08,0x08,0x08,0x08,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02, + 0x00,0x3e,0x51,0x49,0x45,0x3e,0x00,0x00,0x42,0x7f,0x40,0x00,0x00,0x62,0x51,0x49, + 0x49,0x46,0x00,0x22,0x49,0x49,0x49,0x36,0x00,0x18,0x14,0x12,0x7f,0x10,0x00,0x2f, + 0x49,0x49,0x49,0x31,0x00,0x3c,0x4a,0x49,0x49,0x30,0x00,0x01,0x71,0x09,0x05,0x03, + 0x00,0x36,0x49,0x49,0x49,0x36,0x00,0x06,0x49,0x49,0x29,0x1e,0x00,0x00,0x6c,0x6c, + 0x00,0x00,0x00,0x00,0xec,0x6c,0x00,0x00,0x00,0x08,0x14,0x22,0x41,0x00,0x00,0x24, + 0x24,0x24,0x24,0x24,0x00,0x00,0x41,0x22,0x14,0x08,0x00,0x02,0x01,0x59,0x09,0x06, + 0x00,0x3e,0x41,0x5d,0x55,0x1e,0x00,0x7e,0x11,0x11,0x11,0x7e,0x00,0x7f,0x49,0x49, + 0x49,0x36,0x00,0x3e,0x41,0x41,0x41,0x22,0x00,0x7f,0x41,0x41,0x41,0x3e,0x00,0x7f, + 0x49,0x49,0x49,0x41,0x00,0x7f,0x09,0x09,0x09,0x01,0x00,0x3e,0x41,0x49,0x49,0x7a, + 0x00,0x7f,0x08,0x08,0x08,0x7f,0x00,0x00,0x41,0x7f,0x41,0x00,0x00,0x30,0x40,0x40, + 0x40,0x3f,0x00,0x7f,0x08,0x14,0x22,0x41,0x00,0x7f,0x40,0x40,0x40,0x40,0x00,0x7f, + 0x02,0x04,0x02,0x7f,0x00,0x7f,0x02,0x04,0x08,0x7f,0x00,0x3e,0x41,0x41,0x41,0x3e, + 0x00,0x7f,0x09,0x09,0x09,0x06,0x00,0x3e,0x41,0x51,0x21,0x5e,0x00,0x7f,0x09,0x09, + 0x19,0x66,0x00,0x26,0x49,0x49,0x49,0x32,0x00,0x01,0x01,0x7f,0x01,0x01,0x00,0x3f, + 0x40,0x40,0x40,0x3f,0x00,0x1f,0x20,0x40,0x20,0x1f,0x00,0x3f,0x40,0x3c,0x40,0x3f, + 0x00,0x63,0x14,0x08,0x14,0x63,0x00,0x07,0x08,0x70,0x08,0x07,0x00,0x71,0x49,0x45, + 0x43,0x00,0x00,0x00,0x7f,0x41,0x41,0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x00,0x00, + 0x41,0x41,0x7f,0x00,0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x80,0x80,0x80,0x80,0x80, + 0x00,0x00,0x03,0x07,0x00,0x00,0x00,0x20,0x54,0x54,0x54,0x78,0x00,0x7f,0x44,0x44, + 0x44,0x38,0x00,0x38,0x44,0x44,0x44,0x28,0x00,0x38,0x44,0x44,0x44,0x7f,0x00,0x38, + 0x54,0x54,0x54,0x08,0x00,0x08,0x7e,0x09,0x09,0x00,0x00,0x18,0xa4,0xa4,0xa4,0x7c, + 0x00,0x7f,0x04,0x04,0x78,0x00,0x00,0x00,0x00,0x7d,0x40,0x00,0x00,0x40,0x80,0x84, + 0x7d,0x00,0x00,0x7f,0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x7f,0x40,0x00,0x00,0x7c, + 0x04,0x18,0x04,0x78,0x00,0x7c,0x04,0x04,0x78,0x00,0x00,0x38,0x44,0x44,0x44,0x38, + 0x00,0xfc,0x44,0x44,0x44,0x38,0x00,0x38,0x44,0x44,0x44,0xfc,0x00,0x44,0x78,0x44, + 0x04,0x08,0x00,0x08,0x54,0x54,0x54,0x20,0x00,0x04,0x3e,0x44,0x24,0x00,0x00,0x3c, + 0x40,0x20,0x7c,0x00,0x00,0x1c,0x20,0x40,0x20,0x1c,0x00,0x3c,0x60,0x30,0x60,0x3c, + 0x00,0x6c,0x10,0x10,0x6c,0x00,0x00,0x9c,0xa0,0x60,0x3c,0x00,0x00,0x64,0x54,0x54, + 0x4c,0x00,0x00,0x08,0x3e,0x41,0x41,0x00,0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x00, + 0x41,0x41,0x3e,0x08,0x00,0x02,0x01,0x02,0x01,0x00,0x00,0x3c,0x26,0x23,0x26,0x3c}; diff --git a/main/i2c_simple_main.c b/main/i2c_simple_main.c index 656527d..d5d826c 100755 --- a/main/i2c_simple_main.c +++ b/main/i2c_simple_main.c @@ -15,6 +15,7 @@ CONDITIONS OF ANY KIND, either express or implied. */ #include +#include #include "esp_log.h" #include "driver/i2c.h" #include "driver/gpio.h" @@ -28,10 +29,12 @@ #include "EMC2101.h" #include "INA260.h" #include "adc.h" +#include "oled.h" static const char *TAG = "i2c-test"; void app_main(void) { + char oled_buf[20]; //test the LEDs // ESP_LOGI(TAG, "Init LEDs!"); @@ -56,6 +59,15 @@ void app_main(void) { EMC2101_set_fan_speed(0.5); vTaskDelay(500 / portTICK_RATE_MS); + //oled + if (OLED_init()) { + OLED_fill(0); // fill with black + snprintf(oled_buf, 20, "Hello!"); + OLED_writeString(0, 0, oled_buf); + } else { + ESP_LOGI(TAG, "OLED did not init!\n"); + } + while (1) { ESP_LOGI(TAG, "Fan Speed: %d RPM", EMC2101_get_fan_speed()); ESP_LOGI(TAG, "Chip Temp: %.2f C", EMC2101_get_chip_temp()); @@ -68,6 +80,13 @@ void app_main(void) { //ESP32 ADC tests ESP_LOGI(TAG, "Vcore: %d mV\n", ADC_get_vcore()); + if (OLED_status()) { + memset(oled_buf, 0, 20); + snprintf(oled_buf, 20, "SWARM Running "); + OLED_clearLine(3); + OLED_writeString(0, 3, oled_buf); + } + vTaskDelay(5000 / portTICK_RATE_MS); } diff --git a/main/oled.c b/main/oled.c new file mode 100644 index 0000000..bc36dae --- /dev/null +++ b/main/oled.c @@ -0,0 +1,291 @@ +// OLED SSD1306 using the I2C interface +// Written by Larry Bank (bitbank@pobox.com) +// Project started 1/15/2017 +// +// The I2C writes (through a file handle) can be single or multiple bytes. +// The write mode stays in effect throughout each call to write() +// To write commands to the OLED controller, start a byte sequence with 0x00, +// to write data, start a byte sequence with 0x40, +// The OLED controller is set to "page mode". This divides the display +// into 8 128x8 "pages" or strips. Each data write advances the output +// automatically to the next address. The bytes are arranged such that the LSB +// is the topmost pixel and the MSB is the bottom. +// The font data comes from another source and must be rotated 90 degrees +// (at init time) to match the orientation of the bits on the display memory. +// A copy of the display memory is maintained by this code so that single pixel +// writes can occur without having to read from the display controller. + + +#include +#include +#include + +#include "driver/i2c.h" +#include "esp_log.h" +#include "esp_err.h" + +#include "oled.h" + + +#define I2C_TIMEOUT 1000 +#define OLED_FLIP 0 +#define OLED_INVERT 0 +#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */ + +extern unsigned char ucSmallFont[]; +static int iScreenOffset; // current write offset of screen data +static unsigned char ucScreen[1024]; // local copy of the image buffer +static int oled_type, oled_flip; + +static void write_command(unsigned char); +static esp_err_t write(uint8_t *, uint8_t); + +static bool oled_active; + + +//Initialialize the OLED Screen +bool OLED_init(void) { + uint8_t oled32_initbuf[] = { + 0x00, + 0xae, //cmd: display off + 0xd5, //cmd: set display clock + 0x80, + 0xa8, //cmd: set multiplex ratio + 0x1f, //HEIGHT - 1 -> 31 + 0xd3, //cmd: set display offset + 0x00, + 0x40, //cmd: Set Display Start Line + 0x8d, + 0x14, //cmd: Set Higher Column Start Address for Page Addressing Mode + 0xa1, + 0xc8, //cmd: Set COM Output Scan Direction C0/C8 + 0xda, //cmd: Set COM Pins Hardware Configuration + 0x02, // + 0x81, //cmd: Set Contrast control + 0x7f, + 0xd9, //cmd: Set Pre-Charge Period + 0xf1, + 0xdb, //comd: Vcom regulator output + 0x40, + 0xa4, //cmd: display on ram contents + 0xa6, //cmd: set normal + 0xaf}; //cmd: display on + uint8_t uc[4]; + + uint8_t bFlip = OLED_FLIP; + uint8_t bInvert = OLED_INVERT; + oled_active = false; + + // //enable the module + // GPIO_write(Board_OLED_DISP_ENABLE, 0); + // DELAY_MS(50); + // GPIO_write(Board_OLED_DISP_ENABLE, 1); + // DELAY_MS(50); + + oled_type = OLED_128x32; + oled_flip = bFlip; + + // /* Call driver init functions */ + // I2C_init(); + + // /* Create I2C for usage */ + // I2C_Params_init(&oled_i2cParams); + // oled_i2cParams.bitRate = I2C_100kHz; + // oled_i2c = I2C_open(Board_I2C_SSD1306, &oled_i2cParams); + + // if (oled_i2c == NULL) { + // return false; + // } + // oled_active = true; + + write(oled32_initbuf, sizeof(oled32_initbuf)); + + if (bInvert) { + uc[0] = 0; // command + uc[1] = 0xa7; // invert command + write(uc, 2); + } + + if (bFlip) {// rotate display 180 + uc[0] = 0; // command + uc[1] = 0xa0; + write(uc, 2); + uc[1] = 0xc0; + write(uc, 2); + } + return true; +} + +// Sends a command to turn off the OLED display +// Closes the I2C file handle +void OLED_shutdown() { + + write_command(0xaE); // turn off OLED + // I2C_close(oled_i2c); + // GPIO_write(Board_OLED_DISP_ENABLE, 0); //turn off power + oled_active = false; + +} + +// Send a single byte command to the OLED controller +static void write_command(uint8_t c) { + uint8_t buf[2]; + + buf[0] = 0x00; // command introducer + buf[1] = c; + write(buf, 2); +} + +static void oledWriteCommand2(uint8_t c, uint8_t d) { + uint8_t buf[3]; + + buf[0] = 0x00; + buf[1] = c; + buf[2] = d; + write(buf, 3); +} + +bool OLED_setContrast(uint8_t ucContrast) { + + oledWriteCommand2(0x81, ucContrast); + return true; +} + + + +// Send commands to position the "cursor" to the given +// row and column +static void oledSetPosition(int x, int y) { + iScreenOffset = (y*128)+x; + if (oled_type == OLED_64x32) // visible display starts at column 32, row 4 + { + x += 32; // display is centered in VRAM, so this is always true + if (oled_flip == 0) // non-flipped display starts from line 4 + y += 4; + } + else if (oled_type == OLED_132x64) // SH1106 has 128 pixels centered in 132 + { + x += 2; + } + + write_command(0xb0 | y); // go to page Y + write_command(0x00 | (x & 0xf)); // // lower col addr + write_command(0x10 | ((x >> 4) & 0xf)); // upper col addr +} + + +// Write a block of pixel data to the OLED +// Length can be anything from 1 to 1024 (whole display) +static void oledWriteDataBlock(uint8_t *ucBuf, int iLen) { + uint8_t ucTemp[129]; + + ucTemp[0] = 0x40; // data command + memcpy(&ucTemp[1], ucBuf, iLen); + write(ucTemp, iLen+1); + // Keep a copy in local buffer + memcpy(&ucScreen[iScreenOffset], ucBuf, iLen); + iScreenOffset += iLen; +} + +// Set (or clear) an individual pixel +// The local copy of the frame buffer is used to avoid +// reading data from the display controller +int OLED_setPixel(int x, int y, uint8_t ucColor) { + int i; + uint8_t uc, ucOld; + + // if (oled_i2c == NULL) + // return -1; + + i = ((y >> 3) * 128) + x; + if (i < 0 || i > 1023) // off the screen + return -1; + uc = ucOld = ucScreen[i]; + uc &= ~(0x1 << (y & 7)); + if (ucColor) + { + uc |= (0x1 << (y & 7)); + } + if (uc != ucOld) // pixel changed + { + oledSetPosition(x, y>>3); + oledWriteDataBlock(&uc, 1); + } + return 0; +} + + +// +// Draw a string of small (8x8), large (16x24), or very small (6x8) characters +// At the given col+row +// The X position is in character widths (8 or 16) +// The Y position is in memory pages (8 lines each) +// +int OLED_writeString(int x, int y, char *szMsg) { + int i, iLen; + uint8_t *s; + + //if (oled_i2c == NULL) return -1; // not initialized + + iLen = strlen(szMsg); + + oledSetPosition(x*6, y); + if (iLen + x > 21) iLen = 21 - x; + if (iLen < 0) return -1; + for (i=0; i 4) return -1; //line number too big + + memset(temp, 0, 128); + oledSetPosition(0, line); // set to (0,Y) + oledWriteDataBlock(temp, 128); // fill with data byte + + return 0; +} + +bool OLED_status(void) { + return oled_active; +} + + +/** + * @brief Write a byte to a I2C register + */ +static esp_err_t write(uint8_t *data, uint8_t len) { + int ret; + + ret = i2c_master_write_to_device(I2C_MASTER_NUM, 0x3C, data, len, 1000 / portTICK_RATE_MS); + + return ret; +} \ No newline at end of file diff --git a/main/oled.h b/main/oled.h new file mode 100644 index 0000000..2a458a9 --- /dev/null +++ b/main/oled.h @@ -0,0 +1,51 @@ +#ifndef OLED96_H +#define OLED96_H +// +// OLED96 +// Library for accessing the 0.96" SSD1306 128x64 OLED display +// Written by Larry Bank (bitbank@pobox.com) +// Copyright (c) 2017 BitBank Software, Inc. +// Project started 1/15/2017 +// +// OLED type for init function +enum { + OLED_128x32 = 1, + OLED_128x64, + OLED_132x64, + OLED_64x32 +}; + +typedef enum +{ + FONT_NORMAL=0, // 8x8 + FONT_BIG, // 16x24 + FONT_SMALL // 6x8 +} FONTSIZE; + +// Initialize the OLED96 library for a specific I2C address +// Optionally enable inverted or flipped mode +// returns 0 for success, 1 for failure +// +bool OLED_init(void); + +// Turns off the display and closes the I2C handle +void OLED_shutdown(void); + +// Fills the display with the byte pattern +int OLED_fill(uint8_t ucPattern); + +// Write a text string to the display at x (column 0-127) and y (row 0-7) +// bLarge = 0 - 8x8 font, bLarge = 1 - 16x24 font +int OLED_writeString(int x, int y, char *szText); + +// Sets a pixel to On (1) or Off (0) +// Coordinate system is pixels, not text rows (0-127, 0-63) +int OLED_setPixel(int x, int y, uint8_t ucPixel); + +// Sets the contrast (brightness) level of the display +// Valid values are 0-255 where 0=off and 255=max brightness +bool OLED_setContrast(uint8_t ucContrast); +int OLED_clearLine(uint8_t); +bool OLED_status(void); + +#endif // OLED96_H