Add SD card support

Removed_REF_marker
DiSlord 5 years ago
parent a59d7bbb6d
commit 11ddb31ee1

@ -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

@ -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) | \

@ -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
/**

@ -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<<GPIO_SD_CD));
}
static void SD_Select_SPI(uint32_t speed) {
set_SPI_mode(SPI_MODE_SD_CARD);
SPI_BR_SET(SD_SPI, speed); // Set Baud rate control for SD card
SD_CS_LOW; // Select SD Card
}
static void SD_Unselect_SPI(void) {
SD_CS_HIGH; // Unselect SD Card
spi_RxByte(); // Dummy read/write one Byte recommend for SD after CS up
SPI_BR_SET(LCD_SPI, LCD_SPI_SPEED); // Restore Baud rate for LCD
}
//*******************************************************
//* SD functions
//*******************************************************
// CRC7 used for commands
#ifdef SD_USE_COMMAND_CRC
#define CRC7_POLY 0x89
#define CRC7_INIT 0x00
// 7 3
// CRC7 it's a 7 bit CRC with polynomial x + x + 1
static uint8_t crc7(const uint8_t *ptr, uint16_t count) {
uint8_t crc = CRC7_INIT;
uint8_t i = 0;
while (count--){
crc ^= *ptr++;
do{
if (crc & 0x80) crc^=CRC7_POLY;
crc = crc << 1;
} while((++i)&0x7);
}
return crc;
}
#endif
// CRC16 used for data
#ifdef SD_USE_DATA_CRC
#define CRC16_POLY 0x1021
#define CRC16_INIT 0x0000
// 16 12 5
// This is the CCITT CRC 16 polynomial X + X + X + 1.
static uint16_t crc16(const uint8_t *ptr, uint16_t count) {
uint16_t crc = CRC16_INIT;
#if DEBUG == 1
crc_time-= chVTGetSystemTimeX();
#endif
#if 0
uint8_t i = 0;
while(count--){
crc^= ((uint16_t) *ptr++ << 8);
do{
if (crc & 0x8000)
crc = (crc << 1) ^ CRC16_POLY;
else
crc = crc << 1;
} while((++i)&0x7);
}
return __REVSH(crc); // swap bytes
#else
while (count--){
crc^= *ptr++;
crc^= (crc>> 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 {<Start LBA>, <End LBA>} 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)<<n;
res = RES_OK;
}
}
break;
#endif
}
SD_Unselect_SPI();
DEBUG_PRINT("disk_ioctl(%d) = %d,\r\n", cmd, res);
#if DEBUG == 1
testLog();
#endif
return res;
}
#endif //__USE_SD_CARD__

@ -78,7 +78,9 @@
#define __LIMITS__
#define __MCU_CLOCK_SHIFT__
#ifdef TINYSA4
#define __HARMONIC__
#define __USE_RTC__ // Enable RTC clock
#define __USE_SD_CARD__ // Enable SD card support
#define __HARMONIC__
#define __VBW__
#define __SWEEP_RESTART__
#define DB_PER_DEGREE_BELOW 0.056
@ -515,6 +517,9 @@ extern uint16_t graph_bottom;
#define KEYBOARD_BUTTON_BORDER 2
#define FORM_BUTTON_BORDER 2
// Define message box width
#define MESSAGE_BOX_WIDTH 180
// Form button (at center screen better be less LCD_WIDTH - 2*OFFSETX)
#define MENU_FORM_WIDTH (LCD_WIDTH - 2*OFFSETX)
@ -1308,6 +1313,45 @@ void adc_start_analog_watchdog(void);
void adc_stop_analog_watchdog(void);
int16_t adc_vbat_read(void);
/*
* rtc.c
*/
#ifdef __USE_RTC__
#define RTC_START_YEAR 2000
#define RTC_DR_YEAR(dr) (((dr)>>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
*/

@ -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__

@ -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

162
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();

@ -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;

Loading…
Cancel
Save

Powered by TurnKey Linux.