From 11ddb31ee10d78913ee04577061c5bd489ac905d Mon Sep 17 00:00:00 2001 From: DiSlord Date: Tue, 4 May 2021 20:02:44 +0300 Subject: [PATCH] Add SD card support --- Makefile | 2 +- NANOVNA_STM32_F303/board.h | 12 +- halconf.h | 2 +- ili9341.c | 721 +++++++++++++++++++++++++++++++++++++ nanovna.h | 46 ++- rtc.c | 4 +- sa_core.c | 2 +- ui.c | 162 ++++++++- ui_sa.c | 30 +- 9 files changed, 948 insertions(+), 33 deletions(-) diff --git a/Makefile b/Makefile index 831bcaf..be7f79b 100644 --- a/Makefile +++ b/Makefile @@ -260,7 +260,7 @@ CPPWARN = -Wall -Wextra -Wundef ifeq ($(TARGET),F303) UDEFS = -DARM_MATH_CM4 -DVERSION=\"$(VERSION)\" -DTINYSA_F303 -D__FPU_PRESENT -D__FPU_USED -DST7796S -DTINYSA4 #Enable if install external 32.768kHz clock quartz on PC14 and PC15 pins on STM32 CPU -#UDEFS+= -DVNA_USE_LSE +UDEFS+= -DVNA_USE_LSE # Use R as usb pullup UDEFS+= -DUSB_DP_R_VDD #-DCH_DBG_STATISTICS diff --git a/NANOVNA_STM32_F303/board.h b/NANOVNA_STM32_F303/board.h index 5508b20..3c02a6f 100644 --- a/NANOVNA_STM32_F303/board.h +++ b/NANOVNA_STM32_F303/board.h @@ -265,7 +265,7 @@ PIN_MODE_ALTERNATE(GPIOB_SPI_MISO) | \ PIN_MODE_ALTERNATE(GPIOB_SPI_MOSI) | \ PIN_MODE_OUTPUT(6) | \ - PIN_MODE_OUTPUT(7) | \ + PIN_MODE_INPUT(GPIO_SD_CD) | \ PIN_MODE_OUTPUT(8) | \ PIN_MODE_INPUT(9) | \ PIN_MODE_OUTPUT(10) | \ @@ -281,7 +281,7 @@ PIN_OTYPE_PUSHPULL(4) | \ PIN_OTYPE_PUSHPULL(5) | \ PIN_OTYPE_PUSHPULL(6) | \ - PIN_OTYPE_PUSHPULL(7) | \ + PIN_OTYPE_PUSHPULL(GPIO_SD_CD) | \ PIN_OTYPE_PUSHPULL(8) | \ PIN_OTYPE_PUSHPULL(9) | \ PIN_OTYPE_PUSHPULL(10) | \ @@ -297,7 +297,7 @@ PIN_OSPEED_100M(4) | \ PIN_OSPEED_100M(5) | \ PIN_OSPEED_100M(6) | \ - PIN_OSPEED_100M(7) | \ + PIN_OSPEED_2M(GPIO_SD_CD) | \ PIN_OSPEED_100M(8) | \ PIN_OSPEED_100M(9) | \ PIN_OSPEED_100M(10) | \ @@ -313,7 +313,7 @@ PIN_PUPDR_PULLUP(4) | \ PIN_PUPDR_PULLUP(5) | \ PIN_PUPDR_PULLUP(6) | \ - PIN_PUPDR_PULLUP(7) | \ + PIN_PUPDR_PULLUP(GPIO_SD_CD) | \ PIN_PUPDR_PULLUP(8) | \ PIN_PUPDR_PULLUP(9) | \ PIN_PUPDR_PULLUP(10) | \ @@ -329,7 +329,7 @@ PIN_ODR_HIGH(4) | \ PIN_ODR_HIGH(5) | \ PIN_ODR_HIGH(6) | \ - PIN_ODR_HIGH(7) | \ + PIN_ODR_HIGH(GPIO_SD_CD) | \ PIN_ODR_HIGH(8) | \ PIN_ODR_HIGH(9) | \ PIN_ODR_HIGH(10) | \ @@ -345,7 +345,7 @@ PIN_AFIO_AF(GPIOB_SPI_MOSI, 5) | \ PIN_AFIO_AF(GPIOB_SPI_MISO, 5) | \ PIN_AFIO_AF(6, 0) | \ - PIN_AFIO_AF(7, 0)) + PIN_AFIO_AF(GPIO_SD_CD, 0)) #define VAL_GPIOB_AFRH (PIN_AFIO_AF(8, 0) | \ PIN_AFIO_AF(9, 0) | \ PIN_AFIO_AF(10, 0) | \ diff --git a/halconf.h b/halconf.h index b3767eb..251afec 100644 --- a/halconf.h +++ b/halconf.h @@ -122,7 +122,7 @@ * @brief Enables the RTC subsystem. */ #if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) -#define HAL_USE_RTC FALSE +#define HAL_USE_RTC TRUE #endif /** diff --git a/ili9341.c b/ili9341.c index 7c3ba51..327dd47 100644 --- a/ili9341.c +++ b/ili9341.c @@ -343,6 +343,7 @@ static void spi_init(void) static uint16_t current_spi_mode; void set_SPI_mode(uint16_t mode){ if (current_spi_mode == mode) return; + // Disable current mode switch(current_spi_mode){ case SPI_MODE_LCD: break; @@ -352,10 +353,12 @@ void set_SPI_mode(uint16_t mode){ stop_SI4432_SPI_mode(); break; } + // Enable new mode switch(mode){ case SPI_MODE_LCD: break; case SPI_MODE_SD_CARD: + LCD_CS_HIGH; break; case SPI_MODE_SI: LCD_CS_HIGH; @@ -962,3 +965,721 @@ void ili9341_test(int mode) } } #endif + +#ifdef __USE_SD_CARD__ +//***************************************************** +//* SD functions and definitions +//***************************************************** +// Definitions for MMC/SDC command +#define CMD0 (0x40+0) // GO_IDLE_STATE +#define CMD1 (0x40+1) // SEND_OP_COND +#define CMD8 (0x40+8) // SEND_IF_COND +#define CMD9 (0x40+9) // SEND_CSD +#define CMD10 (0x40+10) // SEND_CID +#define CMD12 (0x40+12) // STOP_TRANSMISSION +#define CMD13 (0x40+13) // SEND_STATUS +#define CMD16 (0x40+16) // SET_BLOCKLEN +#define CMD17 (0x40+17) // READ_SINGLE_BLOCK +#define CMD18 (0x40+18) // READ_MULTIPLE_BLOCK +#define CMD23 (0x40+23) // SET_BLOCK_COUNT +#define CMD24 (0x40+24) // WRITE_BLOCK +#define CMD25 (0x40+25) // WRITE_MULTIPLE_BLOCK +#define CMD55 (0x40+55) // APP_CMD +#define CMD58 (0x40+58) // READ_OCR +#define CMD59 (0x40+59) // CRC_ON_OFF +// Then send after CMD55 (APP_CMD) interpret as ACMD +#define ACMD41 (0x40+41) // SEND_OP_COND (ACMD) + +// MMC card type flags (MMC_GET_TYPE) +#define CT_MMC 0x01 // MMC v3 +#define CT_SD1 0x02 // SDv1 +#define CT_SD2 0x04 // SDv2 +#define CT_SDC 0x06 // SD +#define CT_BLOCK 0x08 // Block addressing + +// 7.3.2 Responses +// 7.3.2.1 Format R1 (1 byte) +// This response token is sent by the card after every command with the exception of SEND_STATUS commands. +#define SD_R1_IDLE ((uint8_t)0x01) // The card is in idle state +#define SD_R1_ERASE_RESET ((uint8_t)0x02) // erase reset +#define SD_R1_ILLEGAL_CMD ((uint8_t)0x04) // Illegal command +#define SD_R1_CRC_ERROR ((uint8_t)0x08) // The CRC check of the last command failed +#define SD_R1_ERR_ERASE_CLR ((uint8_t)0x10) // error in the sequence of erase commands +#define SD_R1_ADDR_ERROR ((uint8_t)0x20) // Incorrect address specified +#define SD_R1_PARAM_ERROR ((uint8_t)0x40) // Parameter error +#define SD_R1_NOT_R1 ((uint8_t)0x80) // Not R1 register +// 7.3.2.2 Format R1b (R1 + Busy) +// The busy signal token can be any number of bytes. A zero value indicates card is busy. +// A non-zero value indicates the card is ready for the next command. +// 7.3.2.3 Format R2 (2 byte) +// This response token is two bytes long and sent as a response to the SEND_STATUS command. +// 1 byte - some as R1 +// 2 byte - + +// 7.3.2.4 Format R3 (R1 + OCR, 5 bytes) +// This response token is sent by the card when a READ_OCR command is received. +// 1 byte - some as R1 +// 2-5 byte - OCR +// On Send byte order in SendCommand send MSB first!! +// Received byte order MSB last!! +#define _OCR(dword) (((dword&0x000000FF)<<24)|((dword&0x0000FF00)<<8)|((dword&0x00FF0000)>>8)|((dword&0xFF000000)>>24)) +#define SD_OCR_LOW_VOLTAGE ((uint32_t)0x00000080) // Reserved for Low Voltage Range +#define SD_OCR_27_VOLTAGE ((uint32_t)0x00008000) // VDD Voltage Window 2.7-2.8V +#define SD_OCR_28_VOLTAGE ((uint32_t)0x00010000) // VDD Voltage Window 2.8-2.9V +#define SD_OCR_29_VOLTAGE ((uint32_t)0x00020000) // VDD Voltage Window 2.9-3.0V +#define SD_OCR_30_VOLTAGE ((uint32_t)0x00040000) // VDD Voltage Window 3.0-3.1V +#define SD_OCR_31_VOLTAGE ((uint32_t)0x00080000) // VDD Voltage Window 3.1-3.2V +#define SD_OCR_32_VOLTAGE ((uint32_t)0x00100000) // VDD Voltage Window 3.2-3.3V +#define SD_OCR_33_VOLTAGE ((uint32_t)0x00200000) // VDD Voltage Window 3.3-3.4V +#define SD_OCR_34_VOLTAGE ((uint32_t)0x00400000) // VDD Voltage Window 3.4-3.8V +#define SD_OCR_35_VOLTAGE ((uint32_t)0x00800000) // VDD Voltage Window 3.5-3.6V +#define SD_OCR_18_VOLTAGE ((uint32_t)0x01000000) // VDD Voltage switch to 1.8V (UHS-I only) +#define SD_OCR_CAPACITY ((uint32_t)0x40000000) // Card Capacity Status (CCS) +#define SD_OCR_BUSY ((uint32_t)0x80000000) // Card power up status bit (busy) + +// 5.3 CSD Register +// 16GB Kingston 40 0E 00 32 5B 59 00 00 73 A7 7F 80 0A 40 00 EB // 29608 * 512 kB +// 32GB Samsung 40 0E 00 32 5B 59 00 00 EE 7F 7F 80 0A 40 40 55 // 61056 * 512 kB +// 128GB Samsung 40 0E 00 32 5B 59 00 03 B9 FF 7F 80 0A 40 40 AB // 244224 * 512 kB +#define CSD_0_STRUCTURE 0b11000000 +#define CSD_1_TAAC 0b11111111 +#define CSD_2_NSAC 0b11111111 +#define CSD_3_TRAN_SPEED 0b11111111 +#define CSD_4_CCC 0b11111111 +#define CSD_5_CCC 0b11110000 +#define CSD_5_READ_BL_LEN 0b00001111 +#define CSD_6_READ_BL_PARTIAL 0b10000000 +#define CSD_6_WRITE_BLK_MISALIGN 0b01000000 +#define CSD_6_READ_BLK_MISALIGN 0b00100000 +#define CSD_6_DSR_IMP 0b00010000 +#define CSD_7_C_SIZE 0b00111111 +#define CSD_8_C_SIZE 0b11111111 +#define CSD_9_C_SIZE 0b11111111 +#define CSD_10_ERASE_BLK_EN 0b01000000 +#define CSD_10_SECTOR_SIZE 0b00111111 +#define CSD_11_SECTOR_SIZE 0b10000000 +#define CSD_11_WP_GRP_SIZE 0b01111111 +#define CSD_12_WP_GRP_ENABLE 0b10000000 +#define CSD_12_R2W_FACTOR 0b00011100 +#define CSD_12_WRITE_BL_LEN 0b00000011 +#define CSD_13_WRITE_BL_LEN 0b11000000 +#define CSD_13_WRITE_BL_PARTIAL 0b00100000 +#define CSD_14_FILE_FORMAT_GRP 0b10000000 +#define CSD_14_COPY 0b01000000 +#define CSD_14_PERM_WRITE_PROTECT 0b00100000 +#define CSD_14_TMP_WRITE_PROTECT 0b00010000 +#define CSD_14_FILE_FORMAT 0b00001100 +#define CSD_15_CRC 0b11111110 + + +// 7.3.3.1 Data Response Token +#define SD_TOKEN_DATA_ACCEPTED ((uint8_t)0x05) // Data accepted +#define SD_TOKEN_WRITE_CRC_ERROR ((uint8_t)0x0b) // Data rejected due to a CRC error +#define SD_TOKEN_WRITE_ERROR ((uint8_t)0x0d) // Data rejected due to a write error +// 7.3.3.2 Start Block Tokens and Stop Tran Token +#define SD_TOKEN_START_BLOCK ((uint8_t)0xfe) // Start block (single tx, single/multiple rx) +#define SD_TOKEN_START_M_BLOCK ((uint8_t)0xfc) // Start multiple block tx +#define SD_TOKEN_STOP_M_BLOCK ((uint8_t)0xfd) // Stop multiple block tx +// 7.3.3.3 Data Error Token +#define SD_TOKEN_READ_ERROR ((uint8_t)0x01) // Data read error +#define SD_TOKEN_READ_CC_ERROR ((uint8_t)0x02) // Internal card controller error +#define SD_TOKEN_READ_ECC_ERROR ((uint8_t)0x04) // Card ECC failed +#define SD_TOKEN_READ_RANGE_ERROR ((uint8_t)0x08) // Read address out of range + +//***************************************************** +// SD card module settings +//***************************************************** +// Additional state flag definition +#define STA_POWER_ON 0x80 // Power ON flag + +// Use for enable CRC check of Tx and Rx data on SPI +// If enable both CRC check, on initialization send SD command - CRC_ON_OFF vs ON +// And Card begin check received data and answer on CRC errors +//#define SD_USE_COMMAND_CRC +//#define SD_USE_DATA_CRC + +// Use DMA on sector data Tx to SD card (only if enabled Tx DMA for LCD) +#ifdef __USE_DISPLAY_DMA__ +#define __USE_SDCARD_DMA__ +#endif + +// Use DMA on sector data Rx from SD card (only if enabled Rx DMA for LCD) +#ifdef __USE_DISPLAY_DMA_RX__ +#define __USE_SDCARD_DMA_RX__ +#endif + +// Define sector size +#define SD_SECTOR_SIZE 512 +// SD card spi bus +#define SD_SPI SPI1 +// Define SD SPI speed on work +#define SD_SPI_SPEED SPI_BR_DIV2 +// div4 give less error and high speed for Rx +#define SD_SPI_RX_SPEED SPI_BR_DIV2 + +// Define SD SPI speed on initialization (100-400kHz need) +#define SD_INIT_SPI_SPEED SPI_BR_DIV256 +// Set number of try read or write sector data (1 only one try) +#define SD_READ_WRITE_REPEAT 1 +// Local values for SD card state +static DSTATUS Stat = STA_NOINIT; // Disk Status +static uint8_t CardType = 0; // Type 0:MMC, 1:SDC, 2:Block addressing + +// Debug functions, 0 to disable +#define DEBUG 0 +int shell_printf(const char *fmt, ...); +#define DEBUG_PRINT(...) do { if (DEBUG) shell_printf(__VA_ARGS__); } while (0) +#if DEBUG == 1 +uint32_t w_cnt; +uint32_t w_time; +uint32_t r_cnt; +uint32_t r_time; +uint32_t total_time; +uint32_t crc_time; +void testLog(void){ + DEBUG_PRINT(" Read speed = %d Byte/s (count %d, time %d)\r\n", r_cnt*512*10000/r_time, r_cnt, r_time); + DEBUG_PRINT(" Write speed = %d Byte/s (count %d, time %d)\r\n", w_cnt*512*10000/w_time, w_cnt, w_time); + DEBUG_PRINT(" Total time = %d\r\n", chVTGetSystemTimeX() - total_time); + DEBUG_PRINT(" CRC16 time %d\r\n", crc_time); +} +#endif + +//******************************************************* +// SD card SPI functions +//******************************************************* +#define SD_CS_LOW palClearLine(LINE_SD_CS) +#define SD_CS_HIGH palSetLine(LINE_SD_CS) + +bool SD_Inserted(void){ + return !(palReadPort(GPIOB)&(1<> 4)&0x000F; + crc^= (crc<<12); + crc^= (crc<< 5)&0x1FE0; + crc = __REVSH(crc); // swap bytes + } +#if DEBUG == 1 + crc_time+= chVTGetSystemTimeX(); +#endif + return crc; + #endif +} +#endif + +// Wait and read R1 answer from SD +static inline uint8_t SD_ReadR1(uint32_t cnt) { + uint8_t r1; + // 8th bit R1 always zero, check it + while(((r1=spi_RxByte())&0x80) && --cnt) + ; + return r1; +} + +// Wait SD ready token answer (wait time in systick, 10 systick = 1ms) +static inline bool SD_WaitDataToken(uint8_t token, uint32_t wait_time) { + uint8_t res; + uint32_t time = chVTGetSystemTimeX(); + uint32_t count = 0; + do{ + if ((res = spi_RxByte()) == token) + return true; + count++; + // Check timeout only every 65536 bytes read (~50ms interval) + if ((count&0xFFFF) == 0) + if ((chVTGetSystemTimeX() - time) > wait_time) + break; + }while (res == 0xFF); + return false; +} + +static inline uint8_t SD_WaitDataAccept(uint32_t cnt) { + uint8_t res; + while ((res = spi_RxByte()) == 0xFF && --cnt) + ; + return res&0x1F; +} + +// Wait no Busy answer from SD (wait time in systick, 10 systick = 1ms) +static uint8_t SD_WaitNotBusy(uint32_t wait_time) { + uint8_t res; + uint32_t time = chVTGetSystemTimeX(); + uint32_t count = 0; + do{ + if ((res = spi_RxByte()) == 0xFF) + return res; + count++; + // Check timeout only every 65536 bytes read (~50ms interval) + if ((count&0xFFFF) == 0) + if ((chVTGetSystemTimeX() - time) > wait_time) + break; + }while (1); + return 0; +} + +// Receive data block from SD +static bool SD_RxDataBlock(uint8_t *buff, uint16_t len, uint8_t token) { + // loop until receive read response token or timeout ~50ms + if (!SD_WaitDataToken(token, 500)) { + DEBUG_PRINT(" rx SD_WaitDataToken err\r\n"); + return FALSE; + } + // Receive data (Not use rx DMA) +#ifdef __USE_SDCARD_DMA_RX__ + spi_DMARxBuffer(buff, len, true); +#else + spi_RxBuffer(buff, len); +#endif + // Read and check CRC (if enabled) + uint16_t crc; spi_RxBuffer((uint8_t*)&crc, 2); +#ifdef SD_USE_DATA_CRC + uint16_t bcrc = crc16(buff, len); + if (crc!=bcrc){ + DEBUG_PRINT("CRC = %04x , hcalc = %04x, calc = %04x\r\n", (uint32_t)crc, (uint32_t)bcrc, (uint32_t)crc16(buff, len)); + return FALSE; + } +#endif + return TRUE; +} + +// Transmit data block to SD +static bool SD_TxDataBlock(const uint8_t *buff, uint8_t token) { + uint8_t resp; + // Transmit token + spi_TxByte(token); +#if 0 // Not use multiple block tx + // if it's not STOP token, transmit data, in multiple block Tx + if (token == SD_TOKEN_STOP_BLOCK) return TRUE; +#endif + +#ifdef __USE_SDCARD_DMA__ + spi_DMATxBuffer((uint8_t*)buff, SD_SECTOR_SIZE); +#else + spi_TxBuffer((uint8_t*)buff, SD_SECTOR_SIZE); +#endif + // Send CRC +#ifdef SD_USE_DATA_CRC + uint16_t bcrc = crc16(buff, SD_SECTOR_SIZE); + spi_TxWord(bcrc); +#else + spi_TxWord(0xFFFF); +#endif + spi_DropRx(); + // Receive transmit data response token on next 10 bytes + resp = SD_WaitDataAccept(10); + if (resp != SD_TOKEN_DATA_ACCEPTED){ + goto error_tx; + } +#if 0 + // Wait busy (recommended timeout is 250ms (500ms for SDXC) set 250ms + resp = SD_WaitNotBusy(2500); + if (resp == 0xFF) + return TRUE; +#else + // Continue execute, wait not busy on next command + return TRUE; +#endif + DEBUG_PRINT(" Tx busy error = %04\r\n", (uint32_t)resp); + return FALSE; +error_tx: + DEBUG_PRINT(" Tx accept error = %04x\r\n", (uint32_t)resp); + return FALSE; +} + +// Transmit command to SD +static uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg) { + uint8_t buf[6]; + uint8_t r1; + // wait SD ready after last Tx (recommended timeout is 250ms (500ms for SDXC) set 250ms + if ((r1 = SD_WaitNotBusy(2500)) != 0xFF) { + DEBUG_PRINT(" SD_WaitNotBusy CMD%d err, %02x\r\n", cmd-0x40, (uint32_t)r1); + return 0xFF; + } + // Transmit command + buf[0] = cmd; + buf[1] = (arg >> 24)&0xFF; + buf[2] = (arg >> 16)&0xFF; + buf[3] = (arg >> 8)&0xFF; + buf[4] = (arg >> 0)&0xFF; +#ifdef SD_USE_COMMAND_CRC + buf[5] = crc7(buf, 5)|0x01; +#else + uint8_t crc = 0x01; // Dummy CRC + Stop + if (cmd == CMD0) crc = 0x95;// Valid CRC for CMD0(0) + else if (cmd == CMD8) crc = 0x87;// Valid CRC for CMD8(0x1AA) + buf[5] = crc; +#endif + spi_TxBuffer(buf, 6); + spi_DropRx(); +// Skip a stuff byte when STOP_TRANSMISSION +//if (cmd == CMD12) SPI_RxByte(); + // Receive response register r1 + r1 = SD_ReadR1(10); +#if 1 + if (r1&(SD_R1_NOT_R1|SD_R1_CRC_ERROR|SD_R1_ERASE_RESET|SD_R1_ERR_ERASE_CLR)){ + DEBUG_PRINT(" SD_SendCmd err CMD%d, 0x%x, 0x%08x\r\n", (uint32_t)cmd-0x40, (uint32_t)r1, arg); + return r1; + } + if (r1&(~SD_R1_IDLE)) + DEBUG_PRINT(" SD_SendCmd CMD%d, 0x%x, 0x%08x\r\n", (uint32_t)cmd-0x40, (uint32_t)r1, arg); +#endif + return r1; +} + +// Power on SD +static void SD_PowerOn(void) { + uint16_t n; + SD_Select_SPI(SD_INIT_SPI_SPEED); + + // Dummy TxRx 80 bits for power up SD + for (n=0;n<10;n++) + spi_RxByte(); + // Set SD card to idle state + if (SD_SendCmd(CMD0, 0) == SD_R1_IDLE) + Stat|= STA_POWER_ON; + else{ + Stat = STA_NOINIT; + } + SD_Unselect_SPI(); +} + +// Power off SD +static inline void SD_PowerOff(void) { + Stat &= ~STA_POWER_ON; +} + +// Check power flag +static inline uint8_t SD_CheckPower(void) { + return Stat & STA_POWER_ON; +} + +//******************************************************* +// diskio.c functions for file system library +//******************************************************* +// If enable RTC - get RTC time +#if FF_FS_NORTC == 0 +DWORD get_fattime (void) { + return rtc_get_FAT(); +} +#endif + +// diskio.c - Initialize SD +DSTATUS disk_initialize(BYTE pdrv) { +// Debug counters +#if DEBUG == 1 + w_cnt = 0; + w_time = 0; + r_cnt = 0; + r_time = 0; + crc_time = 0; + total_time = chVTGetSystemTimeX(); +#endif + if (pdrv != 0) return STA_NOINIT; + // power on, try detect on bus, set card to idle state + SD_PowerOn(); + // check disk type + uint8_t type = 0; + uint32_t cnt = 100; + // Set low SPI bus speed = PLL/256 (on 72MHz =281.250kHz) + SD_Select_SPI(SD_INIT_SPI_SPEED); + // send GO_IDLE_STATE command + if (SD_SendCmd(CMD0, 0) == SD_R1_IDLE) + { + DEBUG_PRINT(" CMD0 Ok\r\n"); + // SDC V2+ accept CMD8 command, http://elm-chan.org/docs/mmc/mmc_e.html + if (SD_SendCmd(CMD8, 0x00001AAU) == SD_R1_IDLE) + { + DEBUG_PRINT(" CMD8 Ok\r\n"); + uint32_t ocr; spi_RxBuffer((uint8_t *)&ocr, 4); + DEBUG_PRINT(" CMD8 0x%x\r\n", ocr); + // operation condition register voltage range 2.7-3.6V + if (ocr == _OCR(0x00001AAU)) + { + // ACMD41 with HCS bit can be up to 200ms wait + do { + if (SD_SendCmd(CMD55, 0) <= 1 && // APP_CMD Get Ok or idle state + SD_SendCmd(ACMD41, SD_OCR_CAPACITY) == 0) // Check OCR + break; + chThdSleepMilliseconds(10); + } while (--cnt); + DEBUG_PRINT(" CMD55 + ACMD41 %d\r\n", cnt); + // READ_OCR + if (cnt && SD_SendCmd(CMD58, 0) == 0) + { + DWORD ocr; spi_RxBuffer((uint8_t *)&ocr, 4); + DEBUG_PRINT(" CMD58 OCR = 0x%08X\r\n", _OCR(ocr)); + // Check CCS bit, SDv2 (HC or SC) + type = (ocr & _OCR(SD_OCR_CAPACITY)) ? CT_SD2 | CT_BLOCK : CT_SD2; + } + } +#ifdef SD_USE_COMMAND_CRC +#ifdef SD_USE_DATA_CRC + SD_SendCmd(CMD59, 1); // Enable CRC check on card +#endif +#endif +// uint8_t csd[16]; +// if (SD_SendCmd(CMD9, 0) == 0 && SD_RxDataBlock(csd, 16, SD_TOKEN_START_BLOCK)){ +// DEBUG_PRINT(" CSD ="); +// for (int i = 0; i<16; i++) +// DEBUG_PRINT(" %02X", csd[i]); +// DEBUG_PRINT("\r\n"); +// } + } else { + DEBUG_PRINT(" CMD8 Fail\r\n"); + // SDC V1 or MMC + type = (SD_SendCmd(CMD55, 0) <= 1 && // APP_CMD + SD_SendCmd(ACMD41, 0) <= 1) ? CT_SD1 : CT_MMC; + DEBUG_PRINT(" CMD55 %d\r\n", type); + do{ + if (type == CT_SD1) + { + if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(ACMD41, 0) == 0) break; // ACMD41 + } + else if (SD_SendCmd(CMD1, 0) == 0) break; // CMD1 + chThdSleepMilliseconds(10); + } while (--cnt); + // SET_BLOCKLEN + if (!cnt || SD_SendCmd(CMD16, SD_SECTOR_SIZE) != 0) type = 0; + DEBUG_PRINT(" CMD16 %d %d\r\n", cnt, type); + } + } + SD_Unselect_SPI(); + CardType = type; + DEBUG_PRINT("CardType %d\r\n", type); + // Clear STA_NOINIT and set Power on + if (type){ + Stat&= ~STA_NOINIT; + Stat|= STA_POWER_ON; + } + else // Initialization failed + SD_PowerOff(); + return Stat; +} + +// diskio.c - Return disk status +DSTATUS disk_status(BYTE pdrv) { + if (pdrv != 0) return STA_NOINIT; + return Stat; +} + +// diskio.c - Read sector +DRESULT disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { + // No disk or wrong block count + if (pdrv != 0 || count != 1 || (Stat & STA_NOINIT)) return RES_NOTRDY; + // convert to byte address + if (!(CardType & CT_BLOCK)) sector *= SD_SECTOR_SIZE; + +#if DEBUG == 1 + r_cnt++; + r_time-= chVTGetSystemTimeX(); +#endif + + SD_Select_SPI(SD_SPI_RX_SPEED); + // READ_SINGLE_BLOCK + uint8_t cnt = SD_READ_WRITE_REPEAT; // read repeat count + do{ + if ((SD_SendCmd(CMD17, sector) == 0) && SD_RxDataBlock(buff, SD_SECTOR_SIZE, SD_TOKEN_START_BLOCK)){ + count = 0; + break; + } + }while (--cnt); + SD_Unselect_SPI(); + +#if DEBUG == 1 + r_time+= chVTGetSystemTimeX(); + if (count) + DEBUG_PRINT(" err READ_BLOCK %d 0x%08X\r\n", count, sector); +#if 0 + else{ + DEBUG_PRINT("Sector read 0x%08X %d \r\n", sector, cnt); + for (UINT j = 0; j < 32; j++){ + for (UINT i = 0; i < 16; i++) + DEBUG_PRINT(" 0x%02x", buff[j*16 + i]); + DEBUG_PRINT("\r\n"); + } + } +#endif +#endif + + return count ? RES_ERROR : RES_OK; +} + +// diskio.c - Write sector +DRESULT disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { + // No disk or wrong count + if (pdrv != 0 || count != 1 || (Stat & STA_NOINIT)) return RES_NOTRDY; + // Write protection + if (Stat & STA_PROTECT) return RES_WRPRT; + // Convert to byte address if no Block mode + if (!(CardType & CT_BLOCK)) sector*= SD_SECTOR_SIZE; + + #if DEBUG == 1 +#if 0 + DEBUG_PRINT("Sector write 0x%08X, %d\r\n", sector, count); + for (UINT j = 0; j < 32; j++){ + for (UINT i = 0; i < 16; i++) + DEBUG_PRINT(" 0x%02X", buff[j*16 + i]); + DEBUG_PRINT("\r\n"); + } +#endif + w_cnt++; + w_time-= chVTGetSystemTimeX(); +#endif + + SD_Select_SPI(SD_SPI_SPEED); + // WRITE_SINGLE_BLOCK + uint8_t cnt = SD_READ_WRITE_REPEAT; // write repeat count + do{ + if ((SD_SendCmd(CMD24, sector) == 0) && SD_TxDataBlock(buff, SD_TOKEN_START_BLOCK)){ + count = 0; + break; + } + } while (--cnt); + SD_Unselect_SPI(); + +#if DEBUG == 1 + w_time+= chVTGetSystemTimeX(); + if (count) + DEBUG_PRINT(" WRITE_BLOCK %d 0x%08X\r\n", count, sector); +#endif + + return count ? RES_ERROR : RES_OK; +} + +// The disk_ioctl function is called to control device specific features and miscellaneous functions other than generic read/write. +// Implement only five device independent commands used by FatFS module +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) { + (void)buff; + DRESULT res = RES_PARERR; + // No disk or not ready + if (pdrv != 0 || Stat & STA_NOINIT) return RES_NOTRDY; + SD_Select_SPI(SD_SPI_RX_SPEED); + switch (cmd){ + // Makes sure that the device has finished pending write process. + // If the disk I/O layer or storage device has a write-back cache, + // the dirty cache data must be committed to media immediately. + // Nothing to do for this command if each write operation to the media is completed + // within the disk_write function. + case CTRL_SYNC: + if (SD_WaitNotBusy(2000) == 0xFF) res = RES_OK; + break; +#if FF_USE_TRIM == 1 + // Informs the device the data on the block of sectors is no longer needed and it can be erased. + // The sector block is specified in an LBA_t array {, } pointed by buff. + // This is an identical command to Trim of ATA device. Nothing to do for this command if this function + // is not supported or not a flash memory device. FatFs does not check the result code and the file function + // is not affected even if the sector block was not erased well. This command is called on remove a cluster chain + // and in the f_mkfs function. It is required when FF_USE_TRIM == 1. + case CTRL_TRIM: + break; +#endif +#if FF_MAX_SS > FF_MIN_SS + // Retrieves sector size used for read/write function into the WORD variable pointed by buff. + // Valid sector sizes are 512, 1024, 2048 and 4096. This command is required only if FF_MAX_SS > FF_MIN_SS. + // When FF_MAX_SS == FF_MIN_SS, this command will be never used and the read/write function must work in FF_MAX_SS bytes/sector only. + case GET_SECTOR_SIZE: + *(uint16_t*) buff = SD_SECTOR_SIZE; + res = RES_OK; + break; +#endif +#if FF_USE_MKFS == 1 + // Retrieves erase block size of the flash memory media in unit of sector into the DWORD variable pointed by buff. + // The allowable value is 1 to 32768 in power of 2. Return 1 if the erase block size is unknown or non flash memory media. + // This command is used by only f_mkfs function and it attempts to align data area on the erase block boundary. + // It is required when FF_USE_MKFS == 1. + case GET_BLOCK_SIZE: + *(uint16_t*) buff = ;//SD_SECTOR_SIZE; + res = RES_OK; + break; + // Retrieves number of available sectors, the largest allowable LBA + 1, on the drive into the LBA_t variable pointed by buff. + // This command is used by f_mkfs and f_fdisk function to determine the size of volume/partition to be created. + // It is required when FF_USE_MKFS == 1. + case GET_SECTOR_COUNT: + { + // SEND_CSD + uint8_t csd[16]; + if ((SD_SendCmd(CMD9, 0) == 0) && SD_RxDataBlock(csd, 16, SD_TOKEN_START_BLOCK)) { + uint32_t n, csize; + if ((csd[0] >> 6) == 1) { // SDC V2 + csize = ((uint32_t)csd[7]<<16)|((uint32_t)csd[8]<< 8)|((uint32_t)csd[9]<< 0); + n = 10; + } + else { // MMC or SDC V1 + csize = ((uint32_t)csd[8]>>6)|((uint32_t)csd[7]<<2)|((uint32_t)(csd[6]&0x03)<<10); + n = ((csd[5]&0x0F)|((csd[10]&0x80)>>7)|((csd[9]&0x03)<<1)) + 2 - 9; + } + *(uint32_t*)buff = (csize+1)<>16)&0xFF) +#define RTC_DR_MONTH(dr) (((dr)>> 8)&0xFF) +#define RTC_DR_DAY(dr) (((dr)>> 0)&0xFF) + +#define RTC_TR_HOUR(dr) (((tr)>>16)&0xFF) +#define RTC_TR_MIN(dr) (((tr)>> 8)&0xFF) +#define RTC_TR_SEC(dr) (((tr)>> 0)&0xFF) + +// Init RTC +void rtc_init(void); +// Then read time and date TR should read first, after DR !!! +// Get RTC time as bcd structure in 0x00HHMMSS +#define rtc_get_tr_bcd() (RTC->TR & 0x007F7F7F) +// Get RTC date as bcd structure in 0x00YYMMDD (remove day of week information!!!!) +#define rtc_get_dr_bcd() (RTC->DR & 0x00FF1F3F) +// read TR as 0x00HHMMSS in bin (TR should be read first for sync) +uint32_t rtc_get_tr_bin(void); +// read DR as 0x00YYMMDD in bin (DR should be read second) +uint32_t rtc_get_dr_bin(void); +// Read time in FAT filesystem format +uint32_t rtc_get_FAT(void); +// Write date and time (need in bcd format!!!) +void rtc_set_time(uint32_t dr, uint32_t tr); +#endif + +// SD Card support, discio functions for FatFS lib implemented in ili9341.c +#ifdef __USE_SD_CARD__ +#include "../FatFs/ff.h" +#include "../FatFs/diskio.h" +bool SD_Inserted(void); +void testLog(void); // debug log +#endif + /* * misclinous */ diff --git a/rtc.c b/rtc.c index dee4384..dc83882 100644 --- a/rtc.c +++ b/rtc.c @@ -26,7 +26,7 @@ // Compact STM32 RTC time library #if HAL_USE_RTC == TRUE -#error "Error VNA use self RTC lib, define HAL_USE_RTC = FALSE in halconf.h" +//#error "Error VNA use self RTC lib, define HAL_USE_RTC = FALSE in halconf.h" #endif // Get RTC time as binary structure in 0x00HHMMSS @@ -149,6 +149,7 @@ void rtc_init(void){ // see hal_lld_backup_domain_init() in hal_lld.c for every CPU // Default RTC clock is LSE, but it possible not launch if no quartz installed #endif +#if HAL_USE_RTC == FALSE uint32_t src = RCC->BDCR & STM32_RTCSEL_MASK; if (src == STM32_RTCSEL_NOCLOCK) return; // If calendar has not been initialized yet or different PRER settings then proceed with the initial setup. @@ -170,5 +171,6 @@ void rtc_init(void){ } else RTC->ISR &= ~RTC_ISR_RSF; +#endif } #endif // __USE_RTC__ diff --git a/sa_core.c b/sa_core.c index 221b733..a90f006 100644 --- a/sa_core.c +++ b/sa_core.c @@ -1505,7 +1505,7 @@ static int32_t scaled_correction_multi[CORRECTION_POINTS]; static int32_t scaled_correction_value[CORRECTION_POINTS]; #if 0 // Not implemented -static int8_t scaled_atten_correction[16][16] = +static const int8_t scaled_atten_correction[16][16] = { {0, -1, -2, -2, -3, -4, -3, -1, 0, 3, 7, 14, 21, 30, 42, 54 }, // 2.6G dB*8, 16 levels {0, -2, -4, -6, -7, -9, -8, -8, -11, -9, -9, -8, -7, -4, 2, 8 }, // 3.2G diff --git a/ui.c b/ui.c index e4b13b1..9623a0e 100644 --- a/ui.c +++ b/ui.c @@ -68,6 +68,19 @@ volatile uint8_t operation_requested = OP_NONE; int8_t previous_marker = MARKER_INVALID; +#ifdef __USE_SD_CARD__ +#if SPI_BUFFER_SIZE < 2048 +#error "SPI_BUFFER_SIZE for SD card support need size >= 2048" +#else +// Fat file system work area (at the end of spi_buffer) +static FATFS *fs_volume = (FATFS *)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS)); +// FatFS file object (at the end of spi_buffer) +static FIL *fs_file = ( FIL*)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS) - sizeof(FIL)); +// Filename object (at the end of spi_buffer) +static char *fs_filename = ( char*)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS) - sizeof(FIL) - FF_LFN_BUF - 4); +#endif +#endif + enum { UI_NORMAL, UI_MENU, UI_KEYPAD }; @@ -498,21 +511,34 @@ show_version(void) ili9341_set_background(LCD_BG_COLOR); ili9341_clear_screen(); - uint16_t shift = 0b0000010000111110; + uint16_t shift = 0b00000100001; +// Version text for tinySA3 +#ifdef TINYSA3 ili9341_drawstring_10x14(info_about[i++], x , y); + y+=FONT_GET_HEIGHT*3+3-5; while (info_about[i]) { do {shift>>=1; y+=5;} while (shift&1); - ili9341_drawstring(info_about[i++], x, y+=5); + ili9341_drawstring(info_about[i++], x, y+=FONT_STR_HEIGHT+3-5); } -#ifdef TINYSA3 if (has_esd) - ili9341_drawstring("ESD protected", x, y+=10); + ili9341_drawstring("ESD protected", x, y+=FONT_STR_HEIGHT + 2); + + y+=FONT_STR_HEIGHT + 1; #endif +// Version text for tinySA4 #ifdef TINYSA4 -extern const char *states[]; - #define ENABLE_THREADS_COMMAND + ili9341_drawstring_10x14(info_about[i++], x , y); + y+=FONT_GET_HEIGHT*3+2-5; + ili9341_drawstring_7x13(info_about[i++], x , y); + while (info_about[i]) { + do {shift>>=1; y+=5;} while (shift&1); + ili9341_drawstring_7x13(info_about[i++], x, y+=bFONT_STR_HEIGHT+2-5); + } +extern const char *states[]; +#define ENABLE_THREADS_COMMAND #ifdef ENABLE_THREADS_COMMAND + y+=FONT_STR_HEIGHT + 1; thread_t *tp; tp = chRegFirstThread(); do { @@ -530,13 +556,12 @@ extern const char *states[]; stklimit, (uint32_t)tp->ctx.sp, max_stack_use, (uint32_t)tp, (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], tp->name == NULL ? "" : tp->name); - ili9341_drawstring(buf, x, y+=FONT_STR_HEIGHT); + ili9341_drawstring_7x13(buf, x, y+=bFONT_STR_HEIGHT); tp = chRegNextThread(tp); } while (tp != NULL); #endif - -#endif // TINYSA4 - + y+=bFONT_STR_HEIGHT + 1; +#endif // TINYSA4 uint16_t cnt = 0; while (true) { if (touch_check() == EVT_TOUCH_PRESSED) @@ -545,6 +570,8 @@ extern const char *states[]; break; chThdSleepMilliseconds(40); if ((cnt++)&0x07) continue; // Not update time so fast + +#ifdef TINYSA4 #ifdef __USE_RTC__ uint32_t tr = rtc_get_tr_bin(); // TR read first uint32_t dr = rtc_get_dr_bin(); // DR read second @@ -557,13 +584,14 @@ extern const char *states[]; RTC_TR_MIN(dr), RTC_TR_SEC(dr), (RCC->BDCR & STM32_RTCSEL_MASK) == STM32_RTCSEL_LSE ? 'E' : 'I'); - ili9341_drawstring(buffer, x, y); + ili9341_drawstring_7x13(buf, x, y); #endif #if 0 uint32_t vbat=adc_vbat_read(); plot_printf(buf, sizeof(buf), "Batt: %d.%03dV", vbat/1000, vbat%1000); - ili9341_drawstring(buf, x, y + FONT_STR_HEIGHT + 2); + ili9341_drawstring_7x13(buf, x, y + bFONT_STR_HEIGHT + 1); #endif +#endif // TINYSA4 } } @@ -1546,6 +1574,7 @@ static void draw_button(uint16_t x, uint16_t y, uint16_t w, uint16_t h, ui_button_t *b) { uint16_t bw = b->border&BUTTON_BORDER_WIDTH_MASK; + ili9341_set_foreground(b->fg); ili9341_set_background(b->bg);ili9341_fill(x + bw, y + bw, w - (bw * 2), h - (bw * 2)); if (bw==0) return; uint16_t br = LCD_RISE_EDGE_COLOR; @@ -1555,6 +1584,23 @@ draw_button(uint16_t x, uint16_t y, uint16_t w, uint16_t h, ui_button_t *b) ili9341_set_background(type&BUTTON_BORDER_RIGHT ? br : bd);ili9341_fill(x + w - bw, y, bw, h); // right ili9341_set_background(type&BUTTON_BORDER_LEFT ? br : bd);ili9341_fill(x, y, bw, h); // left ili9341_set_background(type&BUTTON_BORDER_BOTTOM ? br : bd);ili9341_fill(x, y + h - bw, w, bw); // bottom + // Set colors for button text after + ili9341_set_background(b->bg); +} + +static void drawMessageBox(char *header, char *text, uint32_t delay){ + ui_button_t b; + b.bg = LCD_MENU_COLOR; + b.fg = LCD_MENU_TEXT_COLOR; + b.border = BUTTON_BORDER_FLAT|1; + // Draw header + draw_button((LCD_WIDTH-MESSAGE_BOX_WIDTH)/2, LCD_HEIGHT/2-40, MESSAGE_BOX_WIDTH, 60, &b); + ili9341_drawstring_7x13(header, (LCD_WIDTH-MESSAGE_BOX_WIDTH)/2 + 10, LCD_HEIGHT/2-40 + 5); + // Draw window + ili9341_set_background(LCD_FG_COLOR); + ili9341_fill((LCD_WIDTH-MESSAGE_BOX_WIDTH)/2+3, LCD_HEIGHT/2-40+bFONT_STR_HEIGHT+8, MESSAGE_BOX_WIDTH-6, 60-bFONT_STR_HEIGHT-8-3); + ili9341_drawstring_7x13(text, (LCD_WIDTH-MESSAGE_BOX_WIDTH)/2 + 20, LCD_HEIGHT/2-40 + bFONT_STR_HEIGHT + 8 + 14); + chThdSleepMilliseconds(delay); } static void @@ -1574,8 +1620,6 @@ draw_keypad(void) int x = KP_GET_X(keypads[i].x); int y = KP_GET_Y(keypads[i].y); draw_button(x, y, KP_WIDTH, KP_HEIGHT, &button); - ili9341_set_foreground(button.fg); - ili9341_set_background(button.bg); if (keypads[i].c < KP_0) { // KP_0 ili9341_drawfont(keypads[i].c, x + (KP_WIDTH - NUM_FONT_GET_WIDTH) / 2, @@ -1881,9 +1925,6 @@ draw_menu_buttons(const menuitem_t *menu, int only) int button_start = (LCD_WIDTH - MENU_FORM_WIDTH)/2; // At center of screen int button_height = MENU_BUTTON_HEIGHT; draw_button(button_start, y, button_width, button_height, &button); - - ili9341_set_foreground(button.fg); - ili9341_set_background(button.bg); uint16_t text_offs = button_start + 6; if (button.icon >=0){ ili9341_blitBitmap(button_start+3, y+(MENU_BUTTON_HEIGHT-ICON_HEIGHT)/2, ICON_WIDTH, ICON_HEIGHT, &check_box[button.icon*2*ICON_HEIGHT]); @@ -1934,8 +1975,6 @@ draw_menu_buttons(const menuitem_t *menu, int only) int button_start = LCD_WIDTH - MENU_BUTTON_WIDTH; int button_height = MENU_BUTTON_HEIGHT; draw_button(button_start, y, button_width, button_height, &button); - ili9341_set_foreground(button.fg); - ili9341_set_background(button.bg); uint16_t text_offs = button_start + 7; if (button.icon >=0){ ili9341_blitBitmap(button_start+2, y+(MENU_BUTTON_HEIGHT-ICON_HEIGHT)/2, ICON_WIDTH, ICON_HEIGHT, &check_box[button.icon*2*ICON_HEIGHT]); @@ -2838,6 +2877,87 @@ static int touch_quick_menu(int touch_x, int touch_y) return FALSE; } +#ifdef __USE_SD_CARD__ +//******************************************************************************************* +// Bitmap file header for LCD_WIDTH x LCD_HEIGHT image 16bpp (v4 format allow set RGB mask) +//******************************************************************************************* +#define BMP_UINT32(val) ((val)>>0)&0xFF, ((val)>>8)&0xFF, ((val)>>16)&0xFF, ((val)>>24)&0xFF +#define BMP_H1_SIZE (14) // BMP header 14 bytes +#define BMP_V4_SIZE (56) // v4 header 56 bytes +#define BMP_HEAD_SIZE (BMP_H1_SIZE + BMP_V4_SIZE) // Size of all headers +#define BMP_SIZE (2*LCD_WIDTH*LCD_HEIGHT) // Bitmap size = 2*w*h +#define BMP_FILE_SIZE (BMP_SIZE + BMP_HEAD_SIZE) // File size = headers + bitmap +static const uint8_t bmp_header_v4[14+56] = { +// BITMAPFILEHEADER (14 byte size) + 0x42, 0x4D, // BM signature + BMP_UINT32(BMP_FILE_SIZE), // File size (h + v4 + bitmap) + 0x00, 0x00, // reserved + 0x00, 0x00, // reserved + BMP_UINT32(BMP_HEAD_SIZE), // Size of all headers (h + v4) +// BITMAPINFOv4 (56 byte size) + BMP_UINT32(BMP_V4_SIZE), // Data offset after this point (v4 size) + BMP_UINT32(LCD_WIDTH), // Width + BMP_UINT32(LCD_HEIGHT), // Height + 0x01, 0x00, // Planes + 0x10, 0x00, // 16bpp + 0x03, 0x00, 0x00, 0x00, // Compression (BI_BITFIELDS) + BMP_UINT32(BMP_SIZE), // Bitmap size (w*h*2) + 0xC4, 0x0E, 0x00, 0x00, // x Resolution (96 DPI = 96 * 39.3701 inches per metre = 0x0EC4) + 0xC4, 0x0E, 0x00, 0x00, // y Resolution (96 DPI = 96 * 39.3701 inches per metre = 0x0EC4) + 0x00, 0x00, 0x00, 0x00, // Palette size + 0x00, 0x00, 0x00, 0x00, // Palette used +// Extend v4 header data (color mask for RGB565) + 0x00, 0xF8, 0x00, 0x00, // R mask = 0b11111000 00000000 + 0xE0, 0x07, 0x00, 0x00, // G mask = 0b00000111 11100000 + 0x1F, 0x00, 0x00, 0x00, // B mask = 0b00000000 00011111 + 0x00, 0x00, 0x00, 0x00 // A mask = 0b00000000 00000000 +}; + +static bool +made_screenshot(int touch_x, int touch_y) +{ + int y, i; + UINT size; + if (touch_y < HEIGHT || touch_x < FREQUENCIES_XPOS2-100 || touch_x > FREQUENCIES_XPOS2) + return FALSE; + touch_wait_release(); +// uint32_t time = chVTGetSystemTimeX(); +// shell_printf("Screenshot\r\n"); + FRESULT res = f_mount(fs_volume, "", 1); + // fs_volume, fs_file and fs_filename stored at end of spi_buffer!!!!! + uint16_t *buf = (uint16_t *)spi_buffer; +// shell_printf("Mount = %d\r\n", res); + if (res != FR_OK) + return TRUE; +#if FF_USE_LFN >= 1 + uint32_t tr = rtc_get_tr_bcd(); // TR read first + uint32_t dr = rtc_get_dr_bcd(); // DR read second + plot_printf(fs_filename, FF_LFN_BUF, "VNA_%06x_%06x.bmp", dr, tr); +#else + plot_printf(fs_filename, FF_LFN_BUF, "%08x.bmp", rtc_get_FAT()); +#endif + res = f_open(fs_file, fs_filename, FA_CREATE_ALWAYS | FA_READ | FA_WRITE); +// shell_printf("Open %s, result = %d\r\n", fs_filename, res); + if (res == FR_OK){ + res = f_write(fs_file, bmp_header_v4, sizeof(bmp_header_v4), &size); + for (y = LCD_HEIGHT-1; y >= 0 && res == FR_OK; y--) { + ili9341_read_memory(0, y, LCD_WIDTH, 1, buf); + for (i = 0; i < LCD_WIDTH; i++) + buf[i] = __REVSH(buf[i]); // swap byte order (example 0x10FF to 0xFF10) + res = f_write(fs_file, buf, LCD_WIDTH*sizeof(uint16_t), &size); + } + res = f_close(fs_file); +// shell_printf("Close %d\r\n", res); +// testLog(); + } +// time = chVTGetSystemTimeX() - time; +// shell_printf("Total time: %dms (write %d byte/sec)\r\n", time/10, (LCD_WIDTH*LCD_HEIGHT*sizeof(uint16_t)+sizeof(bmp_header_v4))*10000/time); + drawMessageBox("SCREENSHOT", res == FR_OK ? fs_filename : " Fail write ", 2000); + redraw_request|= REDRAW_AREA; + return TRUE; +} +#endif + static int touch_lever_mode_select(int touch_x, int touch_y) { @@ -2940,6 +3060,10 @@ void ui_process_touch(void) break; if (touch_marker_select(touch_x, touch_y)) break; +#ifdef __USE_SD_CARD__ + if (made_screenshot(touch_x, touch_y)) + break; +#endif // Try select lever mode (top and bottom screen) if (touch_lever_mode_select(touch_x, touch_y)) { // touch_wait_release(); diff --git a/ui_sa.c b/ui_sa.c index 65bae12..1c8690c 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -212,7 +212,24 @@ const uint8_t right_icons [] = _BMP16(0b0000000000000000), }; - +const uint8_t sd_icon [] = { +_BMP16(0b1111111111111100), // +_BMP16(0b1000000000000100), // 1 +_BMP16(0b1000000000000100), // 2 +_BMP16(0b1000110011100100), // 5 +_BMP16(0b1001001010010100), // 6 +_BMP16(0b1000100010010100), // 7 +_BMP16(0b1000010010010100), // 8 +_BMP16(0b1001001010010100), // 9 +_BMP16(0b1000110011100100), //10 +_BMP16(0b0100000000000100), // 3 +_BMP16(0b0100000000000100), // 4 +_BMP16(0b1100000000000100), //11 +_BMP16(0b1000000000000100), //12 +_BMP16(0b1000000000000100), //13 +_BMP16(0b0101010101010100), //14 +_BMP16(0b0111111111111100) // +}; #define KP_X(x) (48*(x) + 2 + (LCD_WIDTH-BUTTON_WIDTH-192)) #define KP_Y(y) (48*(y) + 2) @@ -3416,8 +3433,15 @@ redraw_cal_status: strncpy(buf,&VERSION[8], BLEN-1); #endif ili9341_drawstring(buf, x, y); - - +#ifdef __USE_SD_CARD__ + y += YSTEP + YSTEP/2 ; + if (SD_Inserted()){ + ili9341_set_foreground(LCD_BRIGHT_COLOR_GREEN); + ili9341_blitBitmap(x+4, y, FORM_ICON_HEIGHT, FORM_ICON_HEIGHT, sd_icon); +// ili9341_drawstring("-SD-", x, y); + } + y+=12; +#endif if (y >= BATTERY_START && item_space > 0) { item_space--; // Reduce item spacing goto redraw_cal_status;