mirror of
https://github.com/ttrftech/NanoVNA.git
synced 2025-12-06 03:31:59 +01:00
505 lines
12 KiB
C
505 lines
12 KiB
C
/*
|
|
* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
|
|
* All rights reserved.
|
|
*
|
|
* This is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* The software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Radio; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
#include "ch.h"
|
|
#include "hal.h"
|
|
#include "nanovna.h"
|
|
|
|
#define RESET_ASSERT palClearPad(GPIOA, 15)
|
|
#define RESET_NEGATE palSetPad(GPIOA, 15)
|
|
#define CS_LOW palClearPad(GPIOB, 6)
|
|
#define CS_HIGH palSetPad(GPIOB, 6)
|
|
#define DC_CMD palClearPad(GPIOB, 7)
|
|
#define DC_DATA palSetPad(GPIOB, 7)
|
|
|
|
uint16_t spi_buffer[1024];
|
|
|
|
void
|
|
ssp_wait(void)
|
|
{
|
|
while (SPI1->SR & SPI_SR_BSY)
|
|
;
|
|
}
|
|
|
|
void
|
|
ssp_wait_slot(void)
|
|
{
|
|
while ((SPI1->SR & 0x1800) == 0x1800)
|
|
;
|
|
}
|
|
|
|
void
|
|
ssp_senddata(uint8_t x)
|
|
{
|
|
*(uint8_t*)(&SPI1->DR) = x;
|
|
while (SPI1->SR & SPI_SR_BSY)
|
|
;
|
|
}
|
|
|
|
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)
|
|
{
|
|
ssp_wait_slot();
|
|
SPI1->DR = x;
|
|
//while (SPI1->SR & SPI_SR_BSY)
|
|
// ;
|
|
}
|
|
|
|
void
|
|
ssp_databit8(void)
|
|
{
|
|
SPI1->CR2 = (SPI1->CR2 & 0xf0ff) | 0x0700;
|
|
//LPC_SSP1->CR0 = (LPC_SSP1->CR0 & 0xf0) | SSP_DATABIT_8;
|
|
}
|
|
|
|
void
|
|
ssp_databit16(void)
|
|
{
|
|
SPI1->CR2 = (SPI1->CR2 & 0xf0ff) | 0x0f00;
|
|
//LPC_SSP1->CR0 = (LPC_SSP1->CR0 & 0xf0) | SSP_DATABIT_16;
|
|
}
|
|
|
|
|
|
const stm32_dma_stream_t *dmatx;
|
|
uint32_t txdmamode;
|
|
|
|
static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
|
|
(void)spip;
|
|
(void)flags;
|
|
}
|
|
|
|
void
|
|
spi_init(void)
|
|
{
|
|
rccEnableSPI1(FALSE);
|
|
|
|
dmatx = STM32_DMA_STREAM(STM32_SPI_SPI1_TX_DMA_STREAM);
|
|
txdmamode = STM32_DMA_CR_CHSEL(SPI1_TX_DMA_CHANNEL) |
|
|
STM32_DMA_CR_PL(STM32_SPI_SPI1_DMA_PRIORITY) |
|
|
STM32_DMA_CR_DIR_M2P |
|
|
STM32_DMA_CR_DMEIE |
|
|
STM32_DMA_CR_TEIE |
|
|
STM32_DMA_CR_PSIZE_HWORD |
|
|
STM32_DMA_CR_MSIZE_HWORD;
|
|
dmaStreamAllocate(dmatx,
|
|
STM32_SPI_SPI1_IRQ_PRIORITY,
|
|
(stm32_dmaisr_t)spi_lld_serve_tx_interrupt,
|
|
NULL);
|
|
dmaStreamSetPeripheral(dmatx, &SPI1->DR);
|
|
|
|
SPI1->CR1 = 0;
|
|
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;
|
|
}
|
|
|
|
void
|
|
send_command(uint8_t cmd, int len, const uint8_t *data)
|
|
{
|
|
CS_LOW;
|
|
DC_CMD;
|
|
ssp_databit8();
|
|
ssp_senddata(cmd);
|
|
DC_DATA;
|
|
while (len-- > 0) {
|
|
ssp_senddata(*data++);
|
|
}
|
|
//CS_HIGH;
|
|
}
|
|
|
|
void
|
|
send_command16(uint8_t cmd, int data)
|
|
{
|
|
CS_LOW;
|
|
DC_CMD;
|
|
ssp_databit8();
|
|
ssp_senddata(cmd);
|
|
DC_DATA;
|
|
ssp_databit16();
|
|
ssp_senddata16(data);
|
|
CS_HIGH;
|
|
}
|
|
|
|
const uint8_t ili9341_init_seq[] = {
|
|
// cmd, len, data...,
|
|
// Power control B
|
|
0xCF, 3, 0x00, 0x83, 0x30,
|
|
// Power on sequence control
|
|
0xED, 4, 0x64, 0x03, 0x12, 0x81,
|
|
//0xED, 4, 0x55, 0x01, 0x23, 0x01,
|
|
// Driver timing control A
|
|
0xE8, 3, 0x85, 0x01, 0x79,
|
|
//0xE8, 3, 0x84, 0x11, 0x7a,
|
|
// Power control A
|
|
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02,
|
|
// Pump ratio control
|
|
0xF7, 1, 0x20,
|
|
// Driver timing control B
|
|
0xEA, 2, 0x00, 0x00,
|
|
// POWER_CONTROL_1
|
|
0xC0, 1, 0x26,
|
|
// POWER_CONTROL_2
|
|
0xC1, 1, 0x11,
|
|
// VCOM_CONTROL_1
|
|
0xC5, 2, 0x35, 0x3E,
|
|
// VCOM_CONTROL_2
|
|
0xC7, 1, 0xBE,
|
|
// MEMORY_ACCESS_CONTROL
|
|
//0x36, 1, 0x48, // portlait
|
|
0x36, 1, 0x28, // landscape
|
|
// COLMOD_PIXEL_FORMAT_SET : 16 bit pixel
|
|
0x3A, 1, 0x55,
|
|
// Frame Rate
|
|
0xB1, 2, 0x00, 0x1B,
|
|
// Gamma Function Disable
|
|
0xF2, 1, 0x08,
|
|
// gamma set for curve 01/2/04/08
|
|
0x26, 1, 0x01,
|
|
// positive gamma correction
|
|
0xE0, 15, 0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0x87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00,
|
|
// negativ gamma correction
|
|
0xE1, 15, 0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F,
|
|
|
|
// Column Address Set
|
|
0x2A, 4, 0x00, 0x00, 0x01, 0x3f, // width 320
|
|
// Page Address Set
|
|
0x2B, 4, 0x00, 0x00, 0x00, 0xef, // height 240
|
|
|
|
// entry mode
|
|
0xB7, 1, 0x06,
|
|
// display function control
|
|
0xB6, 4, 0x0A, 0x82, 0x27, 0x00,
|
|
|
|
// control display
|
|
//0x53, 1, 0x0c,
|
|
// diaplay brightness
|
|
//0x51, 1, 0xff,
|
|
|
|
// sleep out
|
|
0x11, 0,
|
|
0 // sentinel
|
|
};
|
|
|
|
void
|
|
ili9341_init(void)
|
|
{
|
|
spi_init();
|
|
|
|
DC_DATA;
|
|
RESET_ASSERT;
|
|
chThdSleepMilliseconds(10);
|
|
RESET_NEGATE;
|
|
|
|
send_command(0x01, 0, NULL); // SW reset
|
|
chThdSleepMilliseconds(5);
|
|
send_command(0x28, 0, NULL); // display off
|
|
|
|
const uint8_t *p;
|
|
for (p = ili9341_init_seq; *p; ) {
|
|
send_command(p[0], p[1], &p[2]);
|
|
p += 2 + p[1];
|
|
chThdSleepMilliseconds(5);
|
|
}
|
|
|
|
chThdSleepMilliseconds(100);
|
|
send_command(0x29, 0, NULL); // display on
|
|
}
|
|
|
|
void ili9341_pixel(int x, int y, int color)
|
|
{
|
|
uint8_t xx[4] = { x >> 8, x, (x+1) >> 8, (x+1) };
|
|
uint8_t yy[4] = { y >> 8, y, (y+1) >> 8, (y+1) };
|
|
uint8_t cc[2] = { color >> 8, color };
|
|
send_command(0x2A, 4, xx);
|
|
send_command(0x2B, 4, yy);
|
|
send_command(0x2C, 2, cc);
|
|
//send_command16(0x2C, color);
|
|
}
|
|
|
|
|
|
|
|
void ili9341_fill(int x, int y, int w, int h, int color)
|
|
{
|
|
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) };
|
|
int len = w * h;
|
|
send_command(0x2A, 4, xx);
|
|
send_command(0x2B, 4, yy);
|
|
send_command(0x2C, 0, NULL);
|
|
while (len-- > 0)
|
|
ssp_senddata16(color);
|
|
}
|
|
|
|
#if 0
|
|
void ili9341_bulk(int x, int y, int w, int 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) };
|
|
uint16_t *buf = spi_buffer;
|
|
int len = w * h;
|
|
send_command(0x2A, 4, xx);
|
|
send_command(0x2B, 4, yy);
|
|
send_command(0x2C, 0, NULL);
|
|
while (len-- > 0)
|
|
ssp_senddata16(*buf++);
|
|
}
|
|
#else
|
|
void ili9341_bulk(int x, int y, int w, int 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) };
|
|
int len = w * h;
|
|
|
|
send_command(0x2A, 4, xx);
|
|
send_command(0x2B, 4, yy);
|
|
send_command(0x2C, 0, NULL);
|
|
|
|
dmaStreamSetMemory0(dmatx, spi_buffer);
|
|
dmaStreamSetTransactionSize(dmatx, len);
|
|
dmaStreamSetMode(dmatx, txdmamode | STM32_DMA_CR_MINC);
|
|
dmaStreamEnable(dmatx);
|
|
dmaWaitCompletion(dmatx);
|
|
}
|
|
#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)
|
|
{
|
|
uint16_t *buf = spi_buffer;
|
|
uint8_t bits;
|
|
int c, r;
|
|
for(c = 0; c < 7; c++) {
|
|
bits = x5x7_bits[(ch * 7) + c];
|
|
for (r = 0; r < 5; r++) {
|
|
*buf++ = (0x80 & bits) ? fg : bg;
|
|
bits <<= 1;
|
|
}
|
|
}
|
|
ili9341_bulk(x, y, 5, 7);
|
|
}
|
|
|
|
void
|
|
ili9341_drawstring_5x7(const char *str, int x, int y, uint16_t fg, uint16_t bg)
|
|
{
|
|
while (*str) {
|
|
ili9341_drawchar_5x7(*str, x, y, fg, bg);
|
|
x += 5;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
void
|
|
ili9341_drawchar_size(uint8_t ch, int x, int y, uint16_t fg, uint16_t bg, uint8_t size)
|
|
{
|
|
uint16_t *buf = spi_buffer;
|
|
uint8_t bits;
|
|
int c, r;
|
|
for(c = 0; c < 7*size; c++) {
|
|
bits = x5x7_bits[(ch * 7) + (c / size)];
|
|
for (r = 0; r < 5*size; r++) {
|
|
*buf++ = (0x80 & bits) ? fg : bg;
|
|
if (r % size == (size-1)) {
|
|
bits <<= 1;
|
|
}
|
|
}
|
|
}
|
|
ili9341_bulk(x, y, 5*size, 7*size);
|
|
}
|
|
|
|
void
|
|
ili9341_drawstring_size(const char *str, int x, int y, uint16_t fg, uint16_t bg, uint8_t size)
|
|
{
|
|
while (*str) {
|
|
ili9341_drawchar_size(*str, x, y, fg, bg, size);
|
|
x += 5 * size;
|
|
str++;
|
|
}
|
|
}
|
|
|
|
#define SWAP(x,y) do { int z=x; x = y; y = z; } while(0)
|
|
|
|
void
|
|
ili9341_line(int x0, int y0, int x1, int y1, uint16_t fg)
|
|
{
|
|
if (x0 > x1) {
|
|
SWAP(x0, x1);
|
|
SWAP(y0, y1);
|
|
}
|
|
|
|
while (x0 <= x1) {
|
|
int dx = x1 - x0 + 1;
|
|
int dy = y1 - y0;
|
|
if (dy >= 0) {
|
|
dy++;
|
|
if (dy > dx) {
|
|
dy /= dx; dx = 1;
|
|
} else {
|
|
dx /= dy; dy = 1;
|
|
}
|
|
} else {
|
|
dy--;
|
|
if (-dy > dx) {
|
|
dy /= dx; dx = 1;
|
|
} else {
|
|
dx /= -dy; dy = -1;
|
|
}
|
|
}
|
|
if (dy > 0)
|
|
ili9341_fill(x0, y0, dx, dy, fg);
|
|
else
|
|
ili9341_fill(x0, y0+dy, dx, -dy, fg);
|
|
x0 += dx;
|
|
y0 += dy;
|
|
}
|
|
}
|
|
|
|
|
|
const font_t NF20x24 = { 20, 24, 1, 24, (const uint32_t *)numfont20x24 };
|
|
//const font_t NF32x24 = { 32, 24, 1, 24, (const uint32_t *)numfont32x24 };
|
|
//const font_t NF32x48 = { 32, 48, 2, 24, (const uint32_t *)numfont32x24 };
|
|
|
|
void
|
|
ili9341_drawfont(uint8_t ch, const font_t *font, int x, int y, uint16_t fg, uint16_t bg)
|
|
{
|
|
uint16_t *buf = spi_buffer;
|
|
uint32_t bits;
|
|
const uint32_t *bitmap = &font->bitmap[font->slide * ch];
|
|
int c, r, j;
|
|
|
|
for (c = 0; c < font->slide; c++) {
|
|
for (j = 0; j < font->scaley; j++) {
|
|
bits = bitmap[c];
|
|
for (r = 0; r < font->width; r++) {
|
|
*buf++ = (0x80000000UL & bits) ? fg : bg;
|
|
bits <<= 1;
|
|
}
|
|
}
|
|
}
|
|
ili9341_bulk(x, y, font->width, font->height);
|
|
}
|
|
|
|
#if 0
|
|
const uint16_t colormap[] = {
|
|
RGB565(255,0,0), RGB565(0,255,0), RGB565(0,0,255),
|
|
RGB565(255,255,0), RGB565(0,255,255), RGB565(255,0,255)
|
|
};
|
|
|
|
void
|
|
ili9341_test(int mode)
|
|
{
|
|
int x, y;
|
|
int i;
|
|
switch (mode) {
|
|
default:
|
|
#if 1
|
|
ili9341_fill(0, 0, 320, 240, 0);
|
|
for (y = 0; y < 240; y++) {
|
|
ili9341_fill(0, y, 320, 1, RGB565(y, (y + 120) % 256, 240-y));
|
|
}
|
|
break;
|
|
case 1:
|
|
ili9341_fill(0, 0, 320, 240, 0);
|
|
for (y = 0; y < 240; y++) {
|
|
for (x = 0; x < 320; x++) {
|
|
ili9341_pixel(x, y, (y<<8)|x);
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
//send_command16(0x55, 0xff00);
|
|
ili9341_pixel(64, 64, 0xaa55);
|
|
break;
|
|
#endif
|
|
#if 1
|
|
case 3:
|
|
for (i = 0; i < 10; i++)
|
|
ili9341_drawfont(i, &NF20x24, i*20, 120, colormap[i%6], 0x0000);
|
|
break;
|
|
#endif
|
|
#if 0
|
|
case 4:
|
|
draw_grid(10, 8, 29, 29, 15, 0, 0xffff, 0);
|
|
break;
|
|
#endif
|
|
case 4:
|
|
ili9341_line(0, 0, 15, 100, 0xffff);
|
|
ili9341_line(0, 0, 100, 100, 0xffff);
|
|
ili9341_line(0, 15, 100, 0, 0xffff);
|
|
ili9341_line(0, 100, 100, 0, 0xffff);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|