diff --git a/ili9341.c b/ili9341.c index a39ba1c..586fb6b 100644 --- a/ili9341.c +++ b/ili9341.c @@ -26,11 +26,6 @@ #include "spi.h" -// Allow enable DMA for read display data -#ifdef TINYSA4 -#define __USE_DISPLAY_DMA_RX__ -#endif - // Pin macros for LCD #ifdef TINYSA4 #define LCD_CS_LOW palClearPad(GPIO_LCD_CS_PORT, GPIO_LCD_CS) @@ -48,12 +43,31 @@ #define LCD_DC_DATA palSetPad(GPIOB, GPIOB_LCD_CD) #endif +// LCD display SPI bus #define LCD_SPI SPI1 + +// Custom display definition +#ifdef LCD_DRIVER_ILI9341 // Set SPI bus speed for LCD #define LCD_SPI_SPEED SPI_BR_DIV2 -//Not define if need use some as Tx speed -#ifdef TINYSA4 +// Read speed, need more slow, not define if need use some as Tx speed +//#define LCD_SPI_RX_SPEED SPI_BR_DIV4 +// Allow enable DMA for read display data (can not stable on full speed, on less speed slower) +#define __USE_DISPLAY_DMA_RX__ +#endif + +#ifdef LCD_DRIVER_ST7796S +// Set SPI bus speed for LCD +#define LCD_SPI_SPEED SPI_BR_DIV2 +// Read speed, need more slow, not define if need use some as Tx speed #define LCD_SPI_RX_SPEED SPI_BR_DIV4 +// Allow enable DMA for read display data +#define __USE_DISPLAY_DMA_RX__ +#endif + +// Disable DMA rx on disabled DMA tx +#ifndef __USE_DISPLAY_DMA__ +#undef __USE_DISPLAY_DMA_RX__ #endif pixel_t spi_buffer[SPI_BUFFER_SIZE]; @@ -167,6 +181,50 @@ pixel_t background_color = 0; #define DISPLAY_ROTATION_180 (ILI9341_MADCTL_MX | ILI9341_MADCTL_MY \ | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR) +//***************************************************** +// SPI bus functions, data +//***************************************************** +// SPI transmit byte to SPI (no wait complete transmit) +void spi_TxByte(uint8_t data) { + SPI_WRITE_8BIT(LCD_SPI, data); +} + +// Transmit word to SPI bus (if SPI in 8 bit mode LSB send first!!!!!) +void spi_TxWord(uint16_t data) { + SPI_WRITE_16BIT(LCD_SPI, data); +} + +// Transmit buffer to SPI bus (len should be > 0) +void spi_TxBuffer(uint8_t *buffer, uint16_t len) { + do { + while (SPI_TX_IS_NOT_EMPTY(LCD_SPI)); + SPI_WRITE_8BIT(LCD_SPI, *buffer++); + }while(--len); +} + +// Receive byte from SPI bus +uint8_t spi_RxByte(void) { + // Start RX clock (by sending data) + SPI_WRITE_8BIT(LCD_SPI, 0xFF); + while (SPI_RX_IS_EMPTY(LCD_SPI)||SPI_IS_BUSY(LCD_SPI)); + return SPI_READ_8BIT(LCD_SPI); +} + +// Receive buffer from SPI bus (len should be > 0) +void spi_RxBuffer(uint8_t *buffer, uint16_t len) { + do{ + SPI_WRITE_8BIT(LCD_SPI, 0xFF); + while (SPI_RX_IS_EMPTY(LCD_SPI)); + *buffer++ = SPI_READ_8BIT(LCD_SPI); + }while(--len); +} + +void spi_DropRx(void){ + // Drop Rx buffer after tx and wait tx complete + while (SPI_RX_IS_NOT_EMPTY(LCD_SPI)||SPI_IS_BUSY(LCD_SPI)) + (void)SPI_READ_8BIT(LCD_SPI); +} + //***************************************************** // SPI DMA settings and data //***************************************************** @@ -187,7 +245,6 @@ static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) } #endif -#ifdef __USE_DISPLAY_DMA_RX__ static const stm32_dma_stream_t *dmarx = STM32_DMA_STREAM(STM32_SPI_SPI1_RX_DMA_STREAM); static const uint32_t rxdmamode = STM32_DMA_CR_CHSEL(SPI1_RX_DMA_CHANNEL) // Select SPI1 Rx DMA @@ -202,7 +259,6 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) (void)flags; } #endif -#endif // Send prepared DMA data, and wait completion static void dmaStreamFlush(uint32_t len) @@ -216,60 +272,16 @@ static void dmaStreamFlush(uint32_t len) dmaWaitCompletion(dmatx); } } -#endif - -// SPI transmit byte to SPI (no wait complete transmit) -void spi_TxByte(uint8_t data) { - SPI_WRITE_8BIT(LCD_SPI, data); -} - -// Transmit word to SPI bus (if SPI in 8 bit mode LSB send first!!!!!) -void spi_TxWord(uint16_t data) { - SPI_WRITE_16BIT(LCD_SPI, data); -} - -// Transmit buffer to SPI bus (len should be > 0) -void spi_TxBuffer(uint8_t *buffer, uint16_t len) { - do { - while (SPI_TX_IS_NOT_EMPTY(LCD_SPI)); - SPI_WRITE_8BIT(LCD_SPI, *buffer++); - }while(--len); -} - -// Receive byte from SPI bus -uint8_t spi_RxByte(void) { - // Start RX clock (by sending data) - SPI_WRITE_8BIT(LCD_SPI, 0xFF); - while (SPI_RX_IS_EMPTY(LCD_SPI)||SPI_IS_BUSY(LCD_SPI)); - return SPI_READ_8BIT(LCD_SPI); -} -// Receive buffer from SPI bus (len should be > 0) -void spi_RxBuffer(uint8_t *buffer, uint16_t len) { - do{ - SPI_WRITE_8BIT(LCD_SPI, 0xFF); - while (SPI_RX_IS_EMPTY(LCD_SPI)); - *buffer++ = SPI_READ_8BIT(LCD_SPI); - }while(--len); -} - -void spi_DropRx(void){ - // Drop Rx buffer after tx and wait tx complete - while (SPI_RX_IS_NOT_EMPTY(LCD_SPI)||SPI_IS_BUSY(LCD_SPI)) - (void)SPI_READ_8BIT(LCD_SPI); -} - -#ifdef __USE_DISPLAY_DMA__ // SPI receive byte buffer use DMA void spi_DMATxBuffer(uint8_t *buffer, uint16_t len) { dmaStreamSetMemory0(dmatx, buffer); dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_MINC); dmaStreamFlush(len); } -#ifdef __USE_DISPLAY_DMA_RX__ -#if 0 // Not used + // SPI transmit byte buffer use DMA -static void spi_DMARxBuffer(uint8_t *buffer, uint16_t len) { +void spi_DMARxBuffer(uint8_t *buffer, uint16_t len) { uint8_t dummy_tx = 0xFF; // Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit) dmaStreamSetMemory0(dmarx, buffer); @@ -288,9 +300,7 @@ static void spi_DMARxBuffer(uint8_t *buffer, uint16_t len) { dmaWaitCompletion(dmatx); dmaWaitCompletion(dmarx); } -#endif // 0 -#endif // __USE_DISPLAY_DMA_RX__ -#endif // __USE_DISPLAY_DMA__ +#endif // __USE_DISPLAY_DMA__ static void spi_init(void) { @@ -375,7 +385,7 @@ static void send_command(uint8_t cmd, uint8_t len, const uint8_t *data) //LCD_CS_HIGH; } -#ifdef TINYSA4 +#ifdef LCD_DRIVER_ST7796S static const uint8_t ST7796S_init_seq[] = { // SW reset ILI9341_SOFTWARE_RESET, 0, @@ -419,7 +429,10 @@ static const uint8_t ST7796S_init_seq[] = { ILI9341_DISPLAY_ON, 0, 0 // sentinel }; -#else +#define LCD_INIT ST7796S_init_seq +#endif + +#ifdef LCD_DRIVER_ILI9341 static const uint8_t ili9341_init_seq[] = { // cmd, len, data..., // SW reset @@ -462,9 +475,9 @@ static const uint8_t ili9341_init_seq[] = { // negativ gamma correction ILI9341_NEGATIVE_GAMMA_CORRECTION, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Column Address Set -//ILI9341_COLUMN_ADDRESS_SET, 4, 0x00, 0x00, 0x01, 0x3f, // width 320 +// ILI9341_COLUMN_ADDRESS_SET, 4, 0x00, 0x00, 0x01, 0x3f, // width 320 // Page Address Set -//ILI9341_PAGE_ADDRESS_SET, 4, 0x00, 0x00, 0x00, 0xef, // height 240 +// ILI9341_PAGE_ADDRESS_SET, 4, 0x00, 0x00, 0x00, 0xef, // height 240 // entry mode ILI9341_ENTRY_MODE_SET, 1, 0x06, // display function control @@ -477,7 +490,7 @@ static const uint8_t ili9341_init_seq[] = { ILI9341_DISPLAY_ON, 0, 0 // sentinel }; - +#define LCD_INIT ili9341_init_seq #endif void ili9341_init(void) @@ -488,22 +501,16 @@ void ili9341_init(void) chThdSleepMilliseconds(10); LCD_RESET_NEGATE; const uint8_t *p; -#ifdef TINYSA4 - p = ST7796S_init_seq; -#else - p = ili9341_init_seq; -#endif - while (*p) { + for (p = LCD_INIT; *p; ) { send_command(p[0], p[1], &p[2]); p += 2 + p[1]; chThdSleepMilliseconds(5); } -#ifdef TINYSA4 +// ili9341_clear_screen(); LCD_CS_HIGH; -#endif } -static void ili9341_setWindow(int x, int y, int w, int h){ +static void ili9341_setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h){ //uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) }; //uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) }; uint32_t xx = __REV16(x | ((x + w - 1) << 16)); @@ -512,49 +519,20 @@ static void ili9341_setWindow(int x, int y, int w, int h){ send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t *)&yy); } -#if 0 -// Test code for palette mode -void ili9341_bulk_8bit(int x, int y, int w, int h, pixel_t *palette) -{ - ili9341_setWindow(x, y ,w, h); - send_command(ILI9341_MEMORY_WRITE, 0, NULL); - - uint8_t *buf = (uint8_t *)spi_buffer; - int32_t len = w * h; - while (len-- > 0) - spi_TxWord(palette[*buf++]); -// LCD_CS_HIGH; -} -#endif - -#if DISPLAY_CELL_BUFFER_COUNT != 1 -#define LCD_BUFFER_1 0x01 -#define LCD_DMA_RUN 0x02 -static uint8_t LCD_dma_status = 0; -#endif - -pixel_t *ili9341_get_cell_buffer(void){ -#if DISPLAY_CELL_BUFFER_COUNT == 1 - return spi_buffer; -#else - return &spi_buffer[(LCD_dma_status&LCD_BUFFER_1) ? SPI_BUFFER_SIZE/2 : 0]; -#endif -} - #ifndef __USE_DISPLAY_DMA__ -void ili9341_fill(int x, int y, int w, int h, pixel_t color) +void ili9341_fill(int x, int y, int w, int h) { - ili9341_setWindow(x, y ,w, h); + ili9341_setWindow(x, y, w, h); send_command(ILI9341_MEMORY_WRITE, 0, NULL); uint32_t len = w * h; do { while (SPI_TX_IS_NOT_EMPTY(LCD_SPI)) ; - SPI_WRITE_16BIT(LCD_SPI, color); + SPI_WRITE_16BIT(LCD_SPI, background_color); }while(--len); #ifdef __REMOTE_DESKTOP__ if (auto_capture) { - send_region("fill", x,y,w,h); + send_region("fill", x, y, w, h); send_buffer((uint8_t *)&background_color, 2); } #endif @@ -562,26 +540,18 @@ void ili9341_fill(int x, int y, int w, int h, pixel_t color) void ili9341_bulk(int x, int y, int w, int h) { - ili9341_setWindow(x, y ,w, h); + ili9341_setWindow(x, y, w, h); send_command(ILI9341_MEMORY_WRITE, 0, NULL); spi_TxBuffer((uint8_t *)spi_buffer, w * h * sizeof(pixel_t)); #ifdef __REMOTE_DESKTOP__ if (auto_capture) { - send_region("bulk", x,y,w,h); - send_buffer((uint8_t *)buffer, w *h * sizeof(pixel_t)); + send_region("bulk", x, y, w, h); + send_buffer((uint8_t *)buffer, w * h * sizeof(pixel_t)); } #endif } -void ili9341_bulk_continue(int x, int y, int w, int h){ - ili9341_bulk(x, y, w, h); -} - -void ili9341_bulk_finish(void){ - while (SPI_IS_BUSY(LCD_SPI)); // Wait tx -} - -#else +#else // LCD DMA mode // // Use DMA for send data // @@ -602,12 +572,7 @@ void ili9341_fill(int x, int y, int w, int h) dmaStreamFlush(w * h); } -void ili9341_bulk_finish(void){ - dmaWaitCompletion(dmatx); // Wait DMA - while (SPI_IN_TX_RX(LCD_SPI)); // Wait tx -} - -static void ili9341_DMA_bulk(int x, int y, int w, int h, pixel_t *buffer){ +static void ili9341_DMA_bulk(uint16_t x, uint16_t y, uint16_t w, uint16_t h, pixel_t *buffer){ ili9341_setWindow(x, y ,w, h); send_command(ILI9341_MEMORY_WRITE, 0, NULL); @@ -626,28 +591,46 @@ static void ili9341_DMA_bulk(int x, int y, int w, int h, pixel_t *buffer){ // Copy spi_buffer to region void ili9341_bulk(int x, int y, int w, int h) { - ili9341_DMA_bulk(x, y ,w, h, spi_buffer); // Send data - ili9341_bulk_finish(); // Wait + ili9341_DMA_bulk(x, y, w, h, spi_buffer); // Send data + dmaWaitCompletion(dmatx); +} + +// Used only in double buffer mode +#ifndef ili9341_get_cell_buffer +#define LCD_BUFFER_1 0x01 +#define LCD_DMA_RUN 0x02 +static uint8_t LCD_dma_status = 0; +// Return free buffer for render +pixel_t *ili9341_get_cell_buffer(void){ + return &spi_buffer[(LCD_dma_status&LCD_BUFFER_1) ? SPI_BUFFER_SIZE/2 : 0]; } #endif +// Wait completion before next data send +#ifndef ili9341_bulk_finish +void ili9341_bulk_finish(void){ + dmaWaitCompletion(dmatx); // Wait DMA +//while (SPI_IN_TX_RX(LCD_SPI)); // Wait tx +} +#endif // Copy part of spi_buffer to region, no wait completion after if buffer count !=1 +#ifndef ili9341_bulk_continue void ili9341_bulk_continue(int x, int y, int w, int h) { -#if DISPLAY_CELL_BUFFER_COUNT == 1 - ili9341_bulk(x, y, w, h); -#else - ili9341_bulk_finish(); // Wait DMA - ili9341_DMA_bulk(x, y , w, h, ili9341_get_cell_buffer()); // Send new cell data - LCD_dma_status^=LCD_BUFFER_1; // Switch buffer -#endif + ili9341_bulk_finish(); // Wait DMA + ili9341_DMA_bulk(x, y, w, h, ili9341_get_cell_buffer()); // Send new cell data + LCD_dma_status^=LCD_BUFFER_1; // Switch buffer } +#endif +#endif // end LCD DMA mode -#ifndef __USE_DISPLAY_DMA_RX__ - -void ili9341_read_memory(int x, int y, int w, int h, int len, pixel_t *out) +#ifdef LCD_DRIVER_ILI9341 +// ILI9341 send data in RGB888 format, need parse it +// Copy ILI9341 screen data to buffer +void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out) { - ili9341_setWindow(x, y ,w, h); + uint16_t len = w * h; + ili9341_setWindow(x, y, w, h); send_command(ILI9341_MEMORY_READ, 0, NULL); // Skip data from rx buffer spi_DropRx(); @@ -657,87 +640,58 @@ void ili9341_read_memory(int x, int y, int w, int h, int len, pixel_t *out) #endif // require 8bit dummy clock spi_RxByte(); -#ifdef TINYSA4 // receive pixel data to buffer - spi_RxBuffer((uint8_t *)out, len * 2); +#ifndef __USE_DISPLAY_DMA_RX__ + spi_RxBuffer((uint8_t *)out, len * 3); #else - while (len-- > 0) { - uint8_t r, g, b; - // read data is always 18bit - r = spi_RxByte(); - g = spi_RxByte(); - b = spi_RxByte(); - *out++ = RGB565(r, g, b); - } + spi_DMARxBuffer((uint8_t *)out, len * 3); #endif // restore speed if need #ifdef LCD_SPI_RX_SPEED SPI_BR_SET(LCD_SPI, LCD_SPI_SPEED); #endif LCD_CS_HIGH; + // Parse received data to RGB565 format + uint8_t *rgbbuf = (uint8_t *)out; + while (len-- > 0) { + uint8_t r, g, b; + // read data is always 18bit + r = rgbbuf[0]; + g = rgbbuf[1]; + b = rgbbuf[2]; + *out++ = RGB565(r, g, b); + rgbbuf += 3; + } } +#endif -#else -// Copy screen data to buffer -// Warning!!! buffer size must be greater then 3*len + 1 bytes -void ili9341_read_memory(int x, int y, int w, int h, int len, pixel_t *out) +#ifdef LCD_DRIVER_ST7796S +// ST7796S send data in RGB565 format, not need parse it +// Copy ST7796S screen data to buffer +void ili9341_read_memory(int x, int y, int w, int h, uint16_t *out) { - uint16_t dummy_tx = 0; - uint8_t *rgbbuf = (uint8_t *)out; -#ifdef TINYSA4 - uint16_t data_size = len * 2; - //uint8_t xx[4] = { x >> 8, x, (x+w-1) >> 8, (x+w-1) }; - //uint8_t yy[4] = { y >> 8, y, (y+h-1) >> 8, (y+h-1) }; - uint32_t xx = __REV16(x | ((x + w - 1) << 16)); - uint32_t yy = __REV16(y | ((y + h - 1) << 16)); - send_command(ILI9341_COLUMN_ADDRESS_SET, 4, (uint8_t *)&xx); - send_command(ILI9341_PAGE_ADDRESS_SET, 4, (uint8_t *)&yy); -#else - uint16_t data_size = len * 3; - - ili9341_setWindow(x, y ,w, h); -#endif + uint16_t len = w * h; + ili9341_setWindow(x, y, w, h); send_command(ILI9341_MEMORY_READ, 0, NULL); - - // Init Rx DMA buffer, size, mode (spi and mem data size is 8 bit) - dmaStreamSetMemory0(dmarx, rgbbuf); - dmaStreamSetTransactionSize(dmarx, data_size); - dmaStreamSetMode(dmarx, rxdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE | STM32_DMA_CR_MINC); - // Init dummy Tx DMA (for rx clock), size, mode (spi and mem data size is 8 bit) - dmaStreamSetMemory0(dmatx, &dummy_tx); - dmaStreamSetTransactionSize(dmatx, data_size); - dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE); - // Skip SPI rx buffer + // Skip data from rx buffer spi_DropRx(); // Set read speed (if need different) #ifdef LCD_SPI_RX_SPEED SPI_BR_SET(LCD_SPI, LCD_SPI_RX_SPEED); - #endif +#endif // require 8bit dummy clock spi_RxByte(); - // Start DMA exchange - dmaStreamEnable(dmarx); - dmaStreamEnable(dmatx); - // Wait DMA completion - dmaWaitCompletion(dmatx); - dmaWaitCompletion(dmarx); + // receive pixel data to buffer +#ifndef __USE_DISPLAY_DMA_RX__ + spi_RxBuffer((uint8_t *)out, len * 2); +#else + spi_DMARxBuffer((uint8_t *)out, len * 2); +#endif // restore speed if need #ifdef LCD_SPI_RX_SPEED SPI_BR_SET(LCD_SPI, LCD_SPI_SPEED); #endif LCD_CS_HIGH; -#ifndef TINYSA4 - // Parce recived data - while (len-- > 0) { - uint8_t r, g, b; - // read data is always 18bit - r = rgbbuf[0]; - g = rgbbuf[1]; - b = rgbbuf[2]; - *out++ = RGB565(r, g, b); - rgbbuf += 3; - } -#endif } #endif @@ -746,23 +700,15 @@ void ili9341_clear_screen(void) ili9341_fill(0, 0, ILI9341_WIDTH, ILI9341_HEIGHT); } -#ifndef ili9341_set_foreground void ili9341_set_foreground(uint16_t fg_idx) { - if (fg_idx >= 32) - foreground_color = fg_idx; - else - foreground_color = GET_PALTETTE_COLOR(fg_idx); + foreground_color = GET_PALTETTE_COLOR(fg_idx); } -#endif -#ifndef ili9341_set_background void ili9341_set_background(uint16_t bg_idx) { -// if (bg_idx >= 32) bg_idx = 0; background_color = GET_PALTETTE_COLOR(bg_idx); } -#endif void ili9341_set_rotation(uint8_t r) { @@ -771,11 +717,9 @@ void ili9341_set_rotation(uint8_t r) send_command(ILI9341_MEMORY_ACCESS_CONTROL, 1, &r); } -static uint8_t bit_align = 0; -void ili9341_blitBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, - const uint8_t *b) +void ili9341_blitBitmap(int x, int y, int width, int height, const uint8_t *b) { - uint16_t *buf = spi_buffer; + pixel_t *buf = spi_buffer; uint8_t bits = 0; for (uint16_t c = 0; c < height; c++) { for (uint16_t r = 0; r < width; r++) { @@ -783,7 +727,6 @@ void ili9341_blitBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, *buf++ = (0x80 & bits) ? foreground_color : background_color; bits <<= 1; } - if (bit_align) b+=bit_align; } ili9341_bulk(x, y, width, height); } @@ -828,11 +771,9 @@ void ili9341_drawstring_10x14(const char *str, int x, int y) if (ch == '\n') {x = x_pos; y+=wFONT_STR_HEIGHT; continue;} const uint8_t *char_buf = wFONT_GET_DATA(ch); uint16_t w = wFONT_GET_WIDTH(ch); - bit_align = (w<=8) ? 1 : 0; - ili9341_blitBitmap(x, y, w, wFONT_GET_HEIGHT, char_buf); + ili9341_blitBitmap(x, y, (w<=8) ? 9 : w, wFONT_GET_HEIGHT, char_buf); x += w; } - bit_align = 0; #else ili9341_drawstring_size(str, x, y, 2); #endif diff --git a/main.c b/main.c index 90e9dfa..51f3d08 100644 --- a/main.c +++ b/main.c @@ -184,13 +184,11 @@ static THD_FUNCTION(Thread1, arg) // Process collected data, calculate trace coordinates and plot only if scan // completed if (/* sweep_mode & SWEEP_ENABLE && */ completed) { -#ifdef __VNA__ - if ((domain_mode & DOMAIN_MODE) == DOMAIN_TIME) transform_domain(); -#endif +// START_PROFILE; // Prepare draw graphics, cache all lines, mark screen cells for redraw plot_into_index(measured); redraw_request |= REDRAW_CELLS | REDRAW_BATTERY; - +// STOP_PROFILE; if (uistat.marker_tracking) { int i = marker_search_max(); if (i != -1 && active_marker != MARKER_INVALID) { @@ -358,6 +356,39 @@ int shell_serial_printf(const char *fmt, ...) return formatted_bytes; } #endif + +// +// Function used for search substring v in list +// Example need search parameter "center" in "start|stop|center|span|cw" getStringIndex return 2 +// If not found return -1 +// Used for easy parse command arguments +static int get_str_index(const char *v, const char *list) +{ + int i = 0; + while (1) { + const char *p = v; + while (1) { + char c = *list; + if (c == '|') c = 0; + if (c == *p++) { + // Found, return index + if (c == 0) return i; + list++; // Compare next symbol + continue; + } + break; // Not equal, break + } + // Set new substring ptr + while (1) { + // End of string, not found + if (*list == 0) return -1; + if (*list++ == '|') break; + } + i++; + } + return -1; +} + VNA_SHELL_FUNCTION(cmd_pause) { (void)argc; @@ -386,7 +417,7 @@ VNA_SHELL_FUNCTION(cmd_reset) (void)argv; if (argc == 1) { - if (strcmp(argv[0], "dfu") == 0) { + if (get_str_index(argv[0], "dfu") == 0) { shell_printf("Performing reset to DFU mode\r\n"); enter_dfu(); return; @@ -550,37 +581,6 @@ my_atof(const char *p) return x; } -// -// Function used for search substring v in list -// Example need search parameter "center" in "start|stop|center|span|cw" getStringIndex return 2 -// If not found return -1 -// Used for easy parse command arguments -static int get_str_index(char *v, const char *list) -{ - int i = 0; - while (1) { - char *p = v; - while (1) { - char c = *list; - if (c == '|') c = 0; - if (c == *p++) { - // Found, return index - if (c == 0) return i; - list++; // Compare next symbol - continue; - } - break; // Not equal, break - } - // Set new substring ptr - while (1) { - // End of string, not found - if (*list == 0) return -1; - if (*list++ == '|') break; - } - i++; - } - return -1; -} #ifdef __VNA__ VNA_SHELL_FUNCTION(cmd_offset) { @@ -692,7 +692,7 @@ VNA_SHELL_FUNCTION(cmd_clearconfig) return; } - if (strcmp(argv[0], "1234") != 0) { + if (get_str_index(argv[0], "1234") != 0) { shell_printf("Key unmatched.\r\n"); return; } @@ -802,10 +802,11 @@ VNA_SHELL_FUNCTION(cmd_data) if (argc == 1) sel = my_atoi(argv[0]); - if (sel >= 0 && sel <= MAX_DATA) { + static const uint8_t sel_conv[]={TRACE_TEMP, TRACE_STORED, TRACE_ACTUAL}; + float *data = measured[sel_conv[sel]]; for (i = 0; i < sweep_points; i++) - shell_printf("%f\r\n", value(measured[sel][i])); + shell_printf("%f\r\n", value(data[i])); return; } shell_printf("usage: data [0-2]\r\n"); @@ -888,8 +889,8 @@ VNA_SHELL_FUNCTION(cmd_capture) for (y = 0; y < LCD_HEIGHT; y += 2) { // use uint16_t spi_buffer[2048] (defined in ili9341) for read buffer uint8_t *buf = (uint8_t *)spi_buffer; - ili9341_read_memory(0, y, LCD_WIDTH, 2, 2 * LCD_WIDTH, spi_buffer); - streamWrite(shell_stream, (void*)buf, 2 * 2 * LCD_WIDTH); + ili9341_read_memory(0, y, LCD_WIDTH, 2, spi_buffer); + streamWrite(shell_stream, (void*)buf, 2 * LCD_WIDTH * sizeof(uint16_t)); } } @@ -1176,9 +1177,9 @@ VNA_SHELL_FUNCTION(cmd_scan) if (mask) { for (i = 0; i < points; i++) { if (mask & 1) shell_printf("%U ", frequencies[i]); - if (mask & 2) shell_printf("%f %f ", value(measured[2][i]), 0.0); - if (mask & 4) shell_printf("%f %f ", value(measured[1][i]), 0.0); - if (mask & 8) shell_printf("%f %f ", value(measured[0][i]), 0.0); + if (mask & 2) shell_printf("%f %f ", value(measured[TRACE_ACTUAL][i]), 0.0); + if (mask & 4) shell_printf("%f %f ", value(measured[TRACE_STORED][i]), 0.0); + if (mask & 8) shell_printf("%f %f ", value(measured[TRACE_TEMP][i]), 0.0); shell_printf("\r\n"); } } @@ -1883,7 +1884,7 @@ VNA_SHELL_FUNCTION(cmd_trace) if (argc == 2) { switch (get_str_index(argv[0], cmd_scale_ref_list)) { case 0: - if (strcmp(argv[1],"auto") == 0) { + if (get_str_index(argv[1],"auto") == 0) { set_auto_reflevel(true); } else { user_set_scale(my_atof(argv[1])); @@ -1891,7 +1892,7 @@ VNA_SHELL_FUNCTION(cmd_trace) goto update; case 1: //trace[t].refpos = my_atof(argv[2]); - if (strcmp(argv[1],"auto") == 0) { + if (get_str_index(argv[1],"auto") == 0) { set_auto_reflevel(true); } else { user_set_reflevel(my_atof(argv[1])); @@ -1950,7 +1951,7 @@ VNA_SHELL_FUNCTION(cmd_marker) return; } redraw_request |= REDRAW_MARKER; - if (strcmp(argv[0], "off") == 0) { + if (get_str_index(argv[0], "off") == 0) { active_marker = MARKER_INVALID; for (t = 0; t < MARKERS_MAX; t++) markers[t].enabled = FALSE; @@ -2670,7 +2671,7 @@ static void VNAShell_executeLine(char *line) // Execute line const VNAShellCommand *scp; for (scp = commands; scp->sc_name != NULL; scp++) { - if (strcmp(scp->sc_name, shell_args[0]) == 0) { + if (get_str_index(scp->sc_name, shell_args[0]) == 0) { if (scp->flags & CMD_WAIT_MUTEX) { shell_function = scp->sc_function; operation_requested|=OP_CONSOLE; diff --git a/nanovna.h b/nanovna.h index 893d76d..1187301 100644 --- a/nanovna.h +++ b/nanovna.h @@ -711,7 +711,7 @@ extern volatile uint8_t redraw_request; // Set display buffers count for cell render (if use 2 and DMA, possible send data and prepare new in some time) #ifdef __USE_DISPLAY_DMA__ -// Cell size = sizeof(spi_buffer), but need wait while cell cata send to LCD +// Cell size = sizeof(spi_buffer), but need wait while cell data send to LCD //#define DISPLAY_CELL_BUFFER_COUNT 1 // Cell size = sizeof(spi_buffer)/2, while one cell send to LCD by DMA, CPU render to next cell #define DISPLAY_CELL_BUFFER_COUNT 2 @@ -727,7 +727,7 @@ typedef uint16_t pixel_t; #define CELLHEIGHT (32) // Define size of screen buffer in pixels (one pixel 16bit size) -#define SPI_BUFFER_SIZE (CELLWIDTH*CELLHEIGHT*DISPLAY_CELL_BUFFER_COUNT) +#define SPI_BUFFER_SIZE (CELLWIDTH * CELLHEIGHT * DISPLAY_CELL_BUFFER_COUNT) // SPI bus revert byte order // 16-bit gggBBBbb RRRrrGGG @@ -735,11 +735,13 @@ typedef uint16_t pixel_t; #define RGBHEX(hex) ( (((hex)&0x001c00)<<3) | (((hex)&0x0000f8)<<5) | (((hex)&0xf80000)>>16) | (((hex)&0x00e000)>>13) ) #define HEXRGB(hex) ( (((hex)>>3)&0x001c00) | (((hex)>>5)&0x0000f8) | (((hex)<<16)&0xf80000) | (((hex)<<13)&0x00e000) ) - +// Define LCD display driver and screen size #ifdef TINYSA4 +#define LCD_DRIVER_ST7796S #define LCD_WIDTH 480 #define LCD_HEIGHT 320 #else +#define LCD_DRIVER_ILI9341 #define LCD_WIDTH 320 #define LCD_HEIGHT 240 #endif @@ -813,7 +815,7 @@ typedef uint16_t pixel_t; extern uint16_t foreground_color; extern uint16_t background_color; -extern uint16_t spi_buffer[SPI_BUFFER_SIZE]; +extern pixel_t spi_buffer[SPI_BUFFER_SIZE]; // Used for easy define big Bitmap as 0bXXXXXXXXX image #define _BMP8(d) ((d)&0xFF) @@ -824,16 +826,24 @@ extern uint16_t spi_buffer[SPI_BUFFER_SIZE]; void ili9341_init(void); void ili9341_test(int mode); void ili9341_bulk(int x, int y, int w, int h); // send data to display, in DMA mode use it, but wait DMA complete -void ili9341_bulk_continue(int x, int y, int w, int h); // send data to display, in DMA mode use it, no wait DMA complete -void ili9341_bulk_finish(void); // wait DMA complete (need call at end) void ili9341_fill(int x, int y, int w, int h); + +// Double buffer mode parser +#if DISPLAY_CELL_BUFFER_COUNT == 1 +#define ili9341_get_cell_buffer() spi_buffer +#define ili9341_bulk_continue ili9341_bulk +#define ili9341_bulk_finish() {} +#else pixel_t *ili9341_get_cell_buffer(void); // get buffer for cell render +void ili9341_bulk_continue(int x, int y, int w, int h); // send data to display, in DMA mode use it, no wait DMA complete +void ili9341_bulk_finish(void); // wait DMA complete (need call at end) +#endif void ili9341_set_foreground(uint16_t fg_idx); void ili9341_set_background(uint16_t bg_idx); void ili9341_clear_screen(void); -void ili9341_blitBitmap(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *bitmap); +void ili9341_blitBitmap(int x, int y, int width, int height, const uint8_t *bitmap); void ili9341_drawchar(uint8_t ch, int x, int y); void ili9341_drawstring(const char *str, int x, int y); void ili9341_drawstring_7x13(const char *str, int x, int y); @@ -842,7 +852,7 @@ void ili9341_drawstringV(const char *str, int x, int y); int ili9341_drawchar_size(uint8_t ch, int x, int y, uint8_t size); void ili9341_drawstring_size(const char *str, int x, int y, uint8_t size); void ili9341_drawfont(uint8_t ch, int x, int y); -void ili9341_read_memory(int x, int y, int w, int h, int len, pixel_t* out); +void ili9341_read_memory(int x, int y, int w, int h, uint16_t* out); void ili9341_line(int x0, int y0, int x1, int y1); void show_version(void); diff --git a/plot.c b/plot.c index 9d6fb4c..f369db3 100644 --- a/plot.c +++ b/plot.c @@ -111,7 +111,9 @@ char marker_letter[5] = 'T' }; -//#define float2int(v) ((int)(v)) +#if 1 +#define float2int(v) ((int)(v)) +#else static int float2int(float v) { @@ -119,6 +121,7 @@ float2int(float v) if (v > 0) return v + 0.5; return 0; } +#endif void update_grid(void) { @@ -287,7 +290,8 @@ draw_on_strut(int v0, int d, int color) #define POW_SQRT ((float)0.2236067950725555419921875) #define LOG_10_SQRT_50_x20_plus30 ((float)46.98970004336) #define LOG_10_SQRT_50_x20_plus90 ((float)106.98970004336) - +#define LOG_DIV_10 ((float)0.2302585093) +#define LOG_DIV_20 ((float)0.11512925465) /* * calculate log10f(abs(gamma)) */ @@ -304,20 +308,17 @@ value(const float v) { case U_DBMV: // return v + 30.0 + 20.0*log10f(sqrtf(50)); - return v + LOG_10_SQRT_50_x20_plus30; // + 30.0 + 20.0*LOG_10_SQRT_50; //TODO convert constants to single float number as GCC compiler does runtime calculation - break; + return v + LOG_10_SQRT_50_x20_plus30; // + 30.0 + 20.0*LOG_10_SQRT_50; case U_DBUV: -// return v + 90.0 + 20.0*log10f(sqrtf(50.0)); //TODO convert constants to single float number as GCC compiler does runtime calculation +// return v + 90.0 + 20.0*log10f(sqrtf(50.0)); return v + LOG_10_SQRT_50_x20_plus90; // 90.0 + 20.0*LOG_10_SQRT_50; - break; case U_VOLT: // return powf(10.0, (v-30.0)/20.0) * sqrtf(50.0); -// return powf(10.0, (v-30.0)/20.0) * SQRT_50; // - return powf(10.0, v/20) * POW_SQRT; // powf(10.0,v/20.0) * powf(10, -30.0/20.0) * sqrtf(50) - break; +// return powf(10.0, (v-30.0)/20.0) * SQRT_50; // powf(10.0,v/20.0) * powf(10, -30.0/20.0) * sqrtf(50) + return expf(v*LOG_DIV_20) * POW_SQRT; // expf(v*logf(10.0)/20.0) * powf(10, -30.0/20.0) * sqrtf(50) case U_WATT: - return powf((float)10.0, v/10.0)/1000.0; // - break; +// return powf(10.0, v/10.0)/1000.0; // powf(10, v/10.0)/1000.0 = expf(v*logf(10.0)/10.0)/1000.0 + return expf(v*LOG_DIV_10)/1000.0; // } // case U_DBM: return v; // raw data is in logmag*10 format @@ -331,18 +332,14 @@ to_dBm(const float v) case U_DBMV: // return v - 30.0 - 20.0*log10f(sqrtf(50)); return v - LOG_10_SQRT_50_x20_plus30; // (30.0 + 20.0*LOG_10_SQRT_50); - break; case U_DBUV: // return v - 90.0 - 20.0*log10f(sqrtf(50.0)); //TODO convert constants to single float number as GCC compiler does runtime calculation return v - LOG_10_SQRT_50_x20_plus90; // (90.0 + 20.0*LOG_10_SQRT_50); - break; case U_VOLT: // return log10f( v / (sqrtf(50.0))) * 20.0 + 30.0 ; return log10f( v / SQRT_50) * 20.0 + 30.0 ; - break; case U_WATT: return log10f(v*1000.0)*10.0; - break; } // case U_DBM: return v; // raw data is in logmag*10 format @@ -1293,7 +1290,8 @@ static void cell_draw_marker_info(int x0, int y0) float level = (actual_t[markers[1].index] + actual_t[markers[2].index])/2.0 - actual_t[markers[0].index]; if (level < -70 || level > 0) break; - int depth =(int) (powf((float)10.0, 2.0 + (level + 6.02) /20.0)); +// int depth =(int) (powf((float)10.0, 2.0 + (level + 6.02) /20.0)); + int depth = expf((2.0 + (level + 6.02))*LOG_DIV_20); #endif plot_printf(buf, sizeof buf, "DEPTH: %3d%%", depth); goto show_computed; @@ -1527,7 +1525,7 @@ int display_test(void) for (int w = 0; w < LCD_WIDTH; w++) { spi_buffer[w] = 0; } - ili9341_read_memory(0, h, LCD_WIDTH, 1, LCD_WIDTH, spi_buffer); + ili9341_read_memory(0, h, LCD_WIDTH, 1, spi_buffer); for (int w = 0; w < LCD_WIDTH; w++) { if (spi_buffer[w] != ((w*h) & 0xfff)) return false; @@ -1544,12 +1542,10 @@ int display_test(void) static void update_waterfall(void){ int i; int w_width = area_width < WIDTH ? area_width : WIDTH; - // Waterfall only in 290 or 145 points -// if (!(sweep_points == 290 || sweep_points == 145)) -// return; +// START_PROFILE; for (i = CHART_BOTTOM-1; i >=graph_bottom+1; i--) { // Scroll down - ili9341_read_memory(OFFSETX, i , w_width, 1, w_width*1, spi_buffer); - ili9341_bulk(OFFSETX, i+1, w_width, 1); + ili9341_read_memory(OFFSETX, i, w_width, 1, spi_buffer); + ili9341_bulk(OFFSETX, i+1, w_width, 1); } index_y_t *index; if (setting.average == AV_OFF) @@ -1605,6 +1601,7 @@ static void update_waterfall(void){ } } ili9341_bulk(OFFSETX, graph_bottom+1, w_width, 1); +// STOP_PROFILE; } int get_waterfall(void) diff --git a/sa_cmd.c b/sa_cmd.c index efd9a65..b66d708 100644 --- a/sa_cmd.c +++ b/sa_cmd.c @@ -144,19 +144,6 @@ VNA_SHELL_FUNCTION(cmd_ultra) VNA_SHELL_FUNCTION(cmd_output) { -#if 0 - if (argc != 1) { - usage: - shell_printf("usage: output on|off\r\n"); - return; - } - if (strcmp(argv[0],"on") == 0) { - setting.mute = false; - } else if (strcmp(argv[0],"off") == 0) { - setting.mute = true; - } else - goto usage; -#endif int m = generic_option_cmd("output", "on|off", argc, argv[0]); if (m>=0) { setting.mute = m; @@ -166,19 +153,17 @@ VNA_SHELL_FUNCTION(cmd_output) VNA_SHELL_FUNCTION(cmd_load) { - if (argc != 1) { - usage: - shell_printf("usage: load 0..4\r\n"); + if (argc != 1) + goto usage; + uint16_t a = my_atoui(argv[0]); + if (a <= 4) { + caldata_recall(a); return; } - int a = my_atoi(argv[0]); - if (0 <= a && a <= 4) { - caldata_recall(a); - } else - goto usage; +usage: + shell_printf("usage: load 0..4\r\n"); } - VNA_SHELL_FUNCTION(cmd_attenuate) { if (argc != 1) { @@ -186,7 +171,7 @@ VNA_SHELL_FUNCTION(cmd_attenuate) shell_printf("usage: attenuate 0..31|auto\r\n"); return; } - if (strcmp(argv[0],"auto") == 0) { + if (get_str_index(argv[0],"auto") == 0) { if (!setting.auto_attenuation) set_auto_attenuation(); } else { @@ -249,6 +234,8 @@ VNA_SHELL_FUNCTION(cmd_levelchange) VNA_SHELL_FUNCTION(cmd_leveloffset) { + // 0 1 2 + static const char cmd_mode_list[] = "low|high|switch"; if (argc == 0) { const char *p = "leveloffset %s %.1f\r\n"; shell_printf(p, "low", config.low_level_offset); @@ -257,30 +244,25 @@ VNA_SHELL_FUNCTION(cmd_leveloffset) shell_printf(p, "high output", config.high_level_output_offset); shell_printf(p, "switch", config.switch_offset); return; - } else if (argc == 2) { - float v = my_atof(argv[1]); - if (strcmp(argv[0],"low") == 0) - config.low_level_offset = v; - else if (strcmp(argv[0],"high") == 0) - config.high_level_offset = v; - else if (strcmp(argv[0],"switch") == 0) - config.switch_offset = v; - else - goto usage; - dirty = true; - } else if (argc == 3 && strcmp(argv[1],"output") == 0) { - float v = my_atof(argv[2]); - if (strcmp(argv[0],"low") == 0) - config.low_level_output_offset = v; - else if (strcmp(argv[0],"high") == 0) - config.high_level_output_offset = v; - else - goto usage; - dirty = true; - } else { - usage: - shell_printf("leveloffset [low|high|switch] {output} [-20..+20]\r\n"); } + int mode = get_str_index(argv[0], cmd_mode_list); + float v; + if (argc == 2) + v = my_atof(argv[1]); + else if (argc == 3 && get_str_index(argv[1], "output") == 0) + v = my_atof(argv[2]); + else + goto usage; + switch (mode){ + case 0: config.low_level_offset = v; break; + case 1: config.high_level_offset = v; break; + case 2: config.switch_offset = v; break; + default: goto usage; + } + dirty = true; + return; +usage: + shell_printf("leveloffset [%s] {output} [-20..+20]\r\n", cmd_mode_list); } VNA_SHELL_FUNCTION(cmd_deviceid) @@ -781,7 +763,7 @@ VNA_SHELL_FUNCTION(cmd_correction) } return; } - if (argc == 1 && (strcmp(argv[0],"reset") == 0)) { + if (argc == 1 && (get_str_index(argv[0],"reset") == 0)) { for (int i=0; i