/* * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard * and is covered by GPLv3 license found in COPYING. */ #include "oled.h" #include "delay.h" #include "stm32l4xx_hal_gpio.h" #include "stm32l4xx_hal_rcc.h" #include "stm32l4xx_hal_dma.h" #include "stm32l4xx_hal_spi.h" #include // Reset and config sequence. // // As measured! No attempt to understand them here. static const uint8_t reset_commands[] = { 174, 32, 0, 64, 161, 168, 63, 200, 211, 0, 218, 18, 213, 128, 217, 241, 219, 48, 129, 255, 164, 166, 141, 20, 175 }; // Bytes to send before sending the 1024 bytes of pixel data. // static const uint8_t before_show[] = { 33, 0, 127, 34, 0, 7 }; // OLED connections: // - all on port A // - all push/pull outputs // #define RESET_PIN GPIO_PIN_6 #define DC_PIN GPIO_PIN_8 #define CS_PIN GPIO_PIN_4 #define SPI_SCK GPIO_PIN_5 #define SPI_MOSI GPIO_PIN_7 HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout); static SPI_HandleTypeDef spi_port; // write_bytes() // static inline void write_bytes(int len, const uint8_t *buf) { // send via SPI(1) HAL_SPI_Transmit(&spi_port, (uint8_t *)buf, len, HAL_MAX_DELAY); } // oled_write_cmd() // void oled_write_cmd(uint8_t cmd) { HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); HAL_GPIO_WritePin(GPIOA, DC_PIN, 0); HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); write_bytes(1, &cmd); HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); } // oled_write_cmd_sequence() // void oled_write_cmd_sequence(int len, const uint8_t *cmds) { for(int i=0; iCR1, CR2, SR // mpy settings: // '0x354', '0x1700', '0x002' // this code: // '0x37c', '0x1700', '0x603' //SPI1->CR1 = 0x354; // write a sequence to reset things oled_write_cmd_sequence(sizeof(reset_commands), reset_commands); } // oled_show_raw() // // No decompression. // void oled_show_raw(uint32_t len, const uint8_t *pixels) { oled_setup(); oled_write_cmd_sequence(sizeof(before_show), before_show); HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); write_bytes(len, pixels); HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); } // oled_show() // // Perform simple RLE decompression. // void oled_show(const uint8_t *pixels) { oled_setup(); oled_write_cmd_sequence(sizeof(before_show), before_show); HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); uint8_t buf[127]; const uint8_t *p = pixels; // NOTE: must also update code in oled_show_progress, which dups this heavily. while(1) { uint8_t hdr = *(p++); if(!hdr) break; uint8_t len = hdr & 0x7f; if(hdr & 0x80) { // random bytes follow memcpy(buf, p, len); p += len; } else { // repeat same byte memset(buf, *p, len); p++; } write_bytes(len, buf); } HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); } // oled_show_progress() // // Perform simple RLE decompression, and add a bar on final screen line. // void oled_show_progress(const uint8_t *pixels, int progress) { oled_setup(); oled_write_cmd_sequence(sizeof(before_show), before_show); HAL_GPIO_WritePin(GPIOA, CS_PIN, 1); HAL_GPIO_WritePin(GPIOA, DC_PIN, 1); HAL_GPIO_WritePin(GPIOA, CS_PIN, 0); uint8_t buf[127]; const uint8_t *p = pixels; const uint16_t p_start = 896; uint32_t p_count = 1280 * progress / 1000; if(p_count > 128) p_count = 128; if(p_count < 0) p_count = 0; bool last_line = false; uint16_t offset = 0; while(1) { uint8_t hdr = *(p++); if(hdr == 0) break; uint8_t len = hdr & 0x7f; if(hdr & 0x80) { // random bytes follow memcpy(buf, p, len); p += len; } else { // repeat same byte memset(buf, *p, len); p++; } if(!last_line && (offset+len) >= p_start) { last_line = true; // adjust so we're aligned w/ last line int h = p_start - offset; if(h) { write_bytes(h, buf); memmove(buf, buf+h, len-h); len -= h; offset += h; } } if(last_line) { for(int j=0; (p_count > 0) && (j