diff --git a/ili9341.c b/ili9341.c index cb5e0ec..6fbb2c4 100644 --- a/ili9341.c +++ b/ili9341.c @@ -52,6 +52,18 @@ ssp_senddata(uint8_t x) ; } +uint8_t +ssp_sendrecvdata(uint8_t x) +{ + while (!(SPI1->SR & SPI_SR_TXE)); + // clear OVR + while (SPI1->SR & SPI_SR_RXNE) (void)SPI1->DR; + + *(uint8_t*)(&SPI1->DR) = x; + while (!(SPI1->SR & SPI_SR_RXNE)); + return SPI1->DR; +} + void ssp_senddata16(uint16_t x) { @@ -104,8 +116,8 @@ spi_init(void) dmaStreamSetPeripheral(dmatx, &SPI1->DR); SPI1->CR1 = 0; - SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_BIDIOE | SPI_CR1_SSM | SPI_CR1_SSI;// | SPI_CR1_BR_1; - SPI1->CR2 = 0x0700 | SPI_CR2_TXDMAEN; + SPI1->CR1 = SPI_CR1_MSTR | SPI_CR1_SSM | SPI_CR1_SSI;// | SPI_CR1_BR_1; + SPI1->CR2 = 0x0700 | SPI_CR2_TXDMAEN | SPI_CR2_FRXTH; SPI1->CR1 |= SPI_CR1_SPE; } @@ -278,6 +290,50 @@ void ili9341_bulk(int x, int y, int w, int h) } #endif +void +ili9341_read_memory_raw(uint8_t cmd, int len, uint16_t* out) +{ + uint8_t r, g, b; + send_command(cmd, 0, NULL); + ssp_databit8(); + + // consume old data + while (!(SPI1->SR & SPI_SR_TXE)); + // clear OVR + while (SPI1->SR & SPI_SR_RXNE) r = SPI1->DR; + + // require 8bit dummy clock + r = ssp_sendrecvdata(0); + + while (len-- > 0) { + // read data is always 18bit + r = ssp_sendrecvdata(0); + g = ssp_sendrecvdata(0); + b = ssp_sendrecvdata(0); + *out++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + } + + CS_HIGH; +} + +void +ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t *out) +{ + 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) }; + + send_command(0x2A, 4, xx); + send_command(0x2B, 4, yy); + + ili9341_read_memory_raw(0x2E, len, out); +} + +void +ili9341_read_memory_continue(int len, uint16_t* out) +{ + ili9341_read_memory_raw(0x3E, len, out); +} + void ili9341_drawchar_5x7(uint8_t ch, int x, int y, uint16_t fg, uint16_t bg) { diff --git a/main.c b/main.c index ae68e19..f18d7dc 100644 --- a/main.c +++ b/main.c @@ -51,6 +51,7 @@ int8_t frequency_updated = FALSE; int8_t sweep_enabled = TRUE; int8_t cal_auto_interpolate = TRUE; int8_t redraw_requested = FALSE; +int8_t stop_the_world = FALSE; static THD_WORKING_AREA(waThread1, 768); static THD_FUNCTION(Thread1, arg) @@ -59,6 +60,11 @@ static THD_FUNCTION(Thread1, arg) chRegSetThreadName("sweep"); while (1) { + if (stop_the_world) { + __WFI(); + continue; + } + if (sweep_enabled) { chMtxLock(&mutex); sweep(); @@ -377,6 +383,45 @@ static void cmd_dump(BaseSequentialStream *chp, int argc, char *argv[]) } #endif +static void cmd_capture(BaseSequentialStream *chp, int argc, char *argv[]) +{ +// read pixel count at one time (PART*2 bytes required for read buffer) +#define PART 320 + (void)argc; + (void)argv; + + chMtxLock(&mutex); + + // pause sweep + stop_the_world = TRUE; + + chThdSleepMilliseconds(1000); + + // use uint16_t spi_buffer[1024] (defined in ili9341) for read buffer + uint16_t *buf = &spi_buffer[0]; + int len = 320 * 240; + int i; + ili9341_read_memory(0, 0, 320, 240, PART, buf); + for (i = 0; i < PART; i++) { + streamPut(chp, buf[i] >> 8); + streamPut(chp, buf[i] & 0xff); + } + + len -= PART; + while (len > 0) { + ili9341_read_memory_continue(PART, buf); + for (i = 0; i < PART; i++) { + streamPut(chp, buf[i] >> 8); + streamPut(chp, buf[i] & 0xff); + } + len -= PART; + } + //*/ + + stop_the_world = FALSE; + chMtxUnlock(&mutex); +} + #if 0 static void cmd_gamma(BaseSequentialStream *chp, int argc, char *argv[]) { @@ -1713,6 +1758,7 @@ static const ShellCommand commands[] = { "trace", cmd_trace }, { "marker", cmd_marker }, { "edelay", cmd_edelay }, + { "capture", cmd_capture }, { NULL, NULL } }; diff --git a/nanovna.h b/nanovna.h index 1ef3ede..e1ea1c6 100644 --- a/nanovna.h +++ b/nanovna.h @@ -256,6 +256,8 @@ void ili9341_fill(int x, int y, int w, int h, int color); void ili9341_drawchar_5x7(uint8_t ch, int x, int y, uint16_t fg, uint16_t bg); void ili9341_drawstring_5x7(const char *str, int x, int y, uint16_t fg, uint16_t bg); void ili9341_drawfont(uint8_t ch, const font_t *font, int x, int y, uint16_t fg, uint16_t bg); +void ili9341_read_memory(int x, int y, int w, int h, int len, uint16_t* out); +void ili9341_read_memory_continue(int len, uint16_t* out); /* diff --git a/python/nanovna.py b/python/nanovna.py index 5fd9e89..aa70ef8 100755 --- a/python/nanovna.py +++ b/python/nanovna.py @@ -4,6 +4,7 @@ import numpy as np import pylab as pl import scipy.signal as signal import time +import struct REF_LEVEL = (1<<9) @@ -188,6 +189,16 @@ class NanoVNA(): x.append(float(line)) self._frequencies = np.array(x) + def capture(self): + from PIL import Image + self.send_command("capture\r") + b = self.serial.read(320 * 240 * 2) + x = struct.unpack(">76800H", b) + # convert pixel format from 565(RGB) to 8888(RGBA) + arr = np.array(x, dtype=np.uint32) + arr = 0xFF000000 + ((arr & 0xF800) >> 8) + ((arr & 0x07E0) << 5) + ((arr & 0x001F) << 19) + return Image.frombuffer('RGBA', (320, 240), arr, 'raw', 'RGBA', 0, 1) + def logmag(self, x): pl.grid(True) pl.plot(self.frequencies, 20*np.log10(np.abs(x))) @@ -323,9 +334,18 @@ if __name__ == '__main__': parser.add_option("-l", "--filter", action="store_true", dest="filter", default=False, help="apply IF filter on raw wave plot") + parser.add_option("-C", "--capture", dest="capture", + help="capture current display to FILE", metavar="FILE") (opt, args) = parser.parse_args() nv = NanoVNA(opt.device or '/dev/cu.usbmodem401') + + if opt.capture: + print("capturing...") + img = nv.capture() + img.save(opt.capture) + exit(0) + nv.set_frequency(opt.freq) nv.set_port(opt.port) nv.set_gain(opt.gain)