From 27d3ce7b95ba984cd48a4b2504131b2974046d70 Mon Sep 17 00:00:00 2001 From: guido Date: Mon, 20 Jan 2020 10:40:53 +0100 Subject: [PATCH] Added SSD1306 library. --- QCX-SSB.ino | 527 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 510 insertions(+), 17 deletions(-) diff --git a/QCX-SSB.ino b/QCX-SSB.ino index 663d41b..891cff1 100644 --- a/QCX-SSB.ino +++ b/QCX-SSB.ino @@ -81,6 +81,493 @@ public: // LCD1602 display in 4-bit mode, RS is pull-up and kept low when idle void noDisplay(){ cmd(0x08); } void createChar(uint8_t l, uint8_t glyph[]){ cmd(0x40 | ((l & 0x7) << 3)); for(int i = 0; i != 8; i++) write(glyph[i]); } }; + +class I2C_ { +public: + #define _DELAY() for(uint8_t i = 0; i != 4; i++) asm("nop"); // 4=731kb/s + #define _I2C_SDA (1<<0) // (1 << 4) // PC4 + #define _I2C_SCL (1<<1) // (1 << 5) // PC5 + #define _I2C_INIT() _I2C_SDA_HI(); _I2C_SCL_HI(); DDRD |= (_I2C_SDA | _I2C_SCL); + #define _I2C_SDA_HI() PORTD |= _I2C_SDA; _DELAY(); + #define _I2C_SDA_LO() PORTD &= ~_I2C_SDA; _DELAY(); + #define _I2C_SCL_HI() PORTD |= _I2C_SCL; _DELAY(); + #define _I2C_SCL_LO() PORTD &= ~_I2C_SCL; _DELAY(); + #define _I2C_START() _I2C_SDA_LO(); _I2C_SCL_LO(); _I2C_SDA_HI(); + #define _I2C_STOP() _I2C_SCL_HI(); _I2C_SDA_HI(); + #define _I2C_SUSPEND() //_I2C_SDA_LO(); // SDA_LO to allow re-use as output port + #define _SendBit(data, bit) \ + if(data & 1 << bit){ \ + _I2C_SDA_HI(); \ + } else { \ + _I2C_SDA_LO(); \ + } \ + _I2C_SCL_HI(); \ + _I2C_SCL_LO(); + inline void start(){ _I2C_INIT(); _I2C_START(); }; + inline void stop() { _I2C_STOP(); _I2C_SUSPEND(); }; + inline void SendByte(uint8_t data){ + _SendBit(data, 7); + _SendBit(data, 6); + _SendBit(data, 5); + _SendBit(data, 4); + _SendBit(data, 3); + _SendBit(data, 2); + _SendBit(data, 1); + _SendBit(data, 0); + _I2C_SDA_HI(); // recv ACK + _DELAY(); // + _I2C_SCL_HI(); + _I2C_SCL_LO(); + } + void SendRegister(uint8_t addr, uint8_t* data, uint8_t n){ + start(); + SendByte(addr << 1); + while(n--) SendByte(*data++); + stop(); + } + //void SendRegister(uint8_t addr, uint8_t val){ SendRegister(addr, &val, 1); } + + void begin(){}; + void beginTransmission(uint8_t addr){ start(); SendByte(addr << 1); }; + bool write(uint8_t byte){ SendByte(byte); return 1; }; + uint8_t endTransmission(){ stop(); return 0; }; +}; +I2C_ Wire; +//#include + +/* // 6x8 technoblogy font +const uint8_t font[]PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, + 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, + 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, + 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00, + 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, + 0x00, 0x80, 0x70, 0x30, 0x00, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, + 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, + 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, 0x00, + 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00, + 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, + 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, + 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00, + 0x41, 0x21, 0x11, 0x09, 0x07, 0x00, + 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, + 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, + 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, + 0x02, 0x01, 0x59, 0x09, 0x06, 0x00, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00, + 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00, + 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, + 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, + 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00, + 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, + 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, + 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00, + 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, + 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, + 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, + 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00, + 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, + 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, + 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, + 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, + 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, + 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, + 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00, + 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, + 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, + 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, + 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, + 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, + 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, + 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00, + 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x03, 0x07, 0x08, 0x00, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, 0x00, + 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, + 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00, + 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, + 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00, + 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, + 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00, + 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00, + 0x38, 0x44, 0x44, 0x44, 0x38, 0x00, + 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00, + 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00, + 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00, + 0x48, 0x54, 0x54, 0x54, 0x24, 0x00, + 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00, + 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00, + 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, + 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, + 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, + 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00, + 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, + 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }; + +#define FONT_W 12//6 +#define FONT_H 2 +#define FONT_STRETCHV 1 +#define FONT_STRETCHH 1//0 +*/ + +// C64 real +const uint8_t font[]PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x4f, 0x4f, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x07, 0x00, 0x00, 0x07, 0x07, 0x00, + 0x14, 0x7f, 0x7f, 0x14, 0x14, 0x7f, 0x7f, 0x14, + 0x00, 0x24, 0x2e, 0x6b, 0x6b, 0x3a, 0x12, 0x00, + 0x00, 0x63, 0x33, 0x18, 0x0c, 0x66, 0x63, 0x00, + 0x00, 0x32, 0x7f, 0x4d, 0x4d, 0x77, 0x72, 0x50, + 0x00, 0x00, 0x00, 0x04, 0x06, 0x03, 0x01, 0x00, + 0x00, 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x41, 0x63, 0x3e, 0x1c, 0x00, 0x00, + 0x08, 0x2a, 0x3e, 0x1c, 0x1c, 0x3e, 0x2a, 0x08, + 0x00, 0x08, 0x08, 0x3e, 0x3e, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x80, 0xe0, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, + 0x00, 0x3e, 0x7f, 0x49, 0x45, 0x7f, 0x3e, 0x00, + 0x00, 0x40, 0x44, 0x7f, 0x7f, 0x40, 0x40, 0x00, + 0x00, 0x62, 0x73, 0x51, 0x49, 0x4f, 0x46, 0x00, + 0x00, 0x22, 0x63, 0x49, 0x49, 0x7f, 0x36, 0x00, + 0x00, 0x18, 0x18, 0x14, 0x16, 0x7f, 0x7f, 0x10, + 0x00, 0x27, 0x67, 0x45, 0x45, 0x7d, 0x39, 0x00, + 0x00, 0x3e, 0x7f, 0x49, 0x49, 0x7b, 0x32, 0x00, + 0x00, 0x03, 0x03, 0x79, 0x7d, 0x07, 0x03, 0x00, + 0x00, 0x36, 0x7f, 0x49, 0x49, 0x7f, 0x36, 0x00, + 0x00, 0x26, 0x6f, 0x49, 0x49, 0x7f, 0x3e, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xe4, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x1c, 0x36, 0x63, 0x41, 0x41, 0x00, + 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, + 0x00, 0x41, 0x41, 0x63, 0x36, 0x1c, 0x08, 0x00, + 0x00, 0x02, 0x03, 0x51, 0x59, 0x0f, 0x06, 0x00, + 0x00, 0x3e, 0x7f, 0x41, 0x4d, 0x4f, 0x2e, 0x00, + 0x00, 0x7c, 0x7e, 0x0b, 0x0b, 0x7e, 0x7c, 0x00, + 0x00, 0x7f, 0x7f, 0x49, 0x49, 0x7f, 0x36, 0x00, + 0x00, 0x3e, 0x7f, 0x41, 0x41, 0x63, 0x22, 0x00, + 0x00, 0x7f, 0x7f, 0x41, 0x63, 0x3e, 0x1c, 0x00, + 0x00, 0x7f, 0x7f, 0x49, 0x49, 0x41, 0x41, 0x00, + 0x00, 0x7f, 0x7f, 0x09, 0x09, 0x01, 0x01, 0x00, + 0x00, 0x3e, 0x7f, 0x41, 0x49, 0x7b, 0x3a, 0x00, + 0x00, 0x7f, 0x7f, 0x08, 0x08, 0x7f, 0x7f, 0x00, + 0x00, 0x00, 0x41, 0x7f, 0x7f, 0x41, 0x00, 0x00, + 0x00, 0x20, 0x60, 0x41, 0x7f, 0x3f, 0x01, 0x00, + 0x00, 0x7f, 0x7f, 0x1c, 0x36, 0x63, 0x41, 0x00, + 0x00, 0x7f, 0x7f, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x7f, 0x7f, 0x06, 0x0c, 0x06, 0x7f, 0x7f, + 0x00, 0x7f, 0x7f, 0x0e, 0x1c, 0x7f, 0x7f, 0x00, + 0x00, 0x3e, 0x7f, 0x41, 0x41, 0x7f, 0x3e, 0x00, + 0x00, 0x7f, 0x7f, 0x09, 0x09, 0x0f, 0x06, 0x00, + 0x00, 0x1e, 0x3f, 0x21, 0x61, 0x7f, 0x5e, 0x00, + 0x00, 0x7f, 0x7f, 0x19, 0x39, 0x6f, 0x46, 0x00, + 0x00, 0x26, 0x6f, 0x49, 0x49, 0x7b, 0x32, 0x00, + 0x00, 0x01, 0x01, 0x7f, 0x7f, 0x01, 0x01, 0x00, + 0x00, 0x3f, 0x7f, 0x40, 0x40, 0x7f, 0x3f, 0x00, + 0x00, 0x1f, 0x3f, 0x60, 0x60, 0x3f, 0x1f, 0x00, + 0x00, 0x7f, 0x7f, 0x30, 0x18, 0x30, 0x7f, 0x7f, + 0x00, 0x63, 0x77, 0x1c, 0x1c, 0x77, 0x63, 0x00, + 0x00, 0x07, 0x0f, 0x78, 0x78, 0x0f, 0x07, 0x00, + 0x00, 0x61, 0x71, 0x59, 0x4d, 0x47, 0x43, 0x00, + 0x00, 0x00, 0x7f, 0x7f, 0x41, 0x41, 0x00, 0x00, + 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, + 0x00, 0x00, 0x41, 0x41, 0x7f, 0x7f, 0x00, 0x00, + 0x00, 0x08, 0x0c, 0xfe, 0xfe, 0x0c, 0x08, 0x00, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x00, 0x01, 0x03, 0x06, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x74, 0x54, 0x54, 0x7c, 0x78, 0x00, + 0x00, 0x7e, 0x7e, 0x48, 0x48, 0x78, 0x30, 0x00, + 0x00, 0x38, 0x7c, 0x44, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x30, 0x78, 0x48, 0x48, 0x7e, 0x7e, 0x00, + 0x00, 0x38, 0x7c, 0x54, 0x54, 0x5c, 0x18, 0x00, + 0x00, 0x00, 0x08, 0x7c, 0x7e, 0x0a, 0x0a, 0x00, + 0x00, 0x98, 0xbc, 0xa4, 0xa4, 0xfc, 0x7c, 0x00, + 0x00, 0x7e, 0x7e, 0x08, 0x08, 0x78, 0x70, 0x00, + 0x00, 0x00, 0x48, 0x7a, 0x7a, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x80, 0xfa, 0x7a, 0x00, + 0x00, 0x7e, 0x7e, 0x10, 0x38, 0x68, 0x40, 0x00, + 0x00, 0x00, 0x42, 0x7e, 0x7e, 0x40, 0x00, 0x00, + 0x00, 0x7c, 0x7c, 0x18, 0x38, 0x1c, 0x7c, 0x78, + 0x00, 0x7c, 0x7c, 0x04, 0x04, 0x7c, 0x78, 0x00, + 0x00, 0x38, 0x7c, 0x44, 0x44, 0x7c, 0x38, 0x00, + 0x00, 0xfc, 0xfc, 0x24, 0x24, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x3c, 0x24, 0x24, 0xfc, 0xfc, 0x00, + 0x00, 0x7c, 0x7c, 0x04, 0x04, 0x0c, 0x08, 0x00, + 0x00, 0x48, 0x5c, 0x54, 0x54, 0x74, 0x24, 0x00, + 0x00, 0x04, 0x04, 0x3e, 0x7e, 0x44, 0x44, 0x00, + 0x00, 0x3c, 0x7c, 0x40, 0x40, 0x7c, 0x7c, 0x00, + 0x00, 0x1c, 0x3c, 0x60, 0x60, 0x3c, 0x1c, 0x00, + 0x00, 0x1c, 0x7c, 0x70, 0x38, 0x70, 0x7c, 0x1c, + 0x00, 0x44, 0x6c, 0x38, 0x38, 0x6c, 0x44, 0x00, + 0x00, 0x9c, 0xbc, 0xa0, 0xe0, 0x7c, 0x3c, 0x00, + 0x00, 0x44, 0x64, 0x74, 0x5c, 0x4c, 0x44, 0x00, + 0x00, 0x08, 0x3e, 0x77, 0x41, 0x41, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x41, 0x41, 0x77, 0x3e, 0x08, 0x00, + 0x00, 0x04, 0x02, 0x02, 0x04, 0x04, 0x02, 0x00 + }; + +#define FONT_W 8 +#define FONT_H 2 +#define FONT_STRETCHV 1 +#define FONT_STRETCHH 0 + +/* //16x8 C-64 kind of +const uint8_t font[]PROGMEM = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0x20 + 0x00,0x06,0x5F,0x5F,0x06,0x00,0x00,0x00, // 0x21 + 0x00,0x07,0x07,0x00,0x07,0x07,0x00,0x00, // 0x22 + 0x14,0x7F,0x7F,0x14,0x7F,0x7F,0x14,0x00, // 0x23 + 0x24,0x2E,0x6B,0x6B,0x3A,0x12,0x00,0x00, // 0x24 + 0x46,0x66,0x30,0x18,0x0C,0x66,0x62,0x00, // 0x25 + 0x30,0x7A,0x4F,0x5D,0x37,0x7A,0x48,0x00, // 0x26 + 0x04,0x07,0x03,0x00,0x00,0x00,0x00,0x00, // 0x27 + 0x00,0x1C,0x3E,0x63,0x41,0x00,0x00,0x00, // 0x28 + 0x00,0x41,0x63,0x3E,0x1C,0x00,0x00,0x00, // 0x29 + 0x08,0x2A,0x3E,0x1C,0x1C,0x3E,0x2A,0x08, // 0x2A + 0x08,0x08,0x3E,0x3E,0x08,0x08,0x00,0x00, // 0x2B + 0x00,0xA0,0xE0,0x60,0x00,0x00,0x00,0x00, // 0x2C + 0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00, // 0x2D + 0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00, // 0x2E + 0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00, // 0x2F + 0x3E,0x7F,0x59,0x4D,0x7F,0x3E,0x00,0x00, // 0x30 + 0x42,0x42,0x7F,0x7F,0x40,0x40,0x00,0x00, // 0x31 + 0x62,0x73,0x59,0x49,0x6F,0x66,0x00,0x00, // 0x32 + 0x22,0x63,0x49,0x49,0x7F,0x36,0x00,0x00, // 0x33 + 0x18,0x1C,0x16,0x13,0x7F,0x7F,0x10,0x00, // 0x34 + 0x27,0x67,0x45,0x45,0x7D,0x39,0x00,0x00, // 0x35 + 0x3C,0x7E,0x4B,0x49,0x79,0x30,0x00,0x00, // 0x36 + 0x03,0x63,0x71,0x19,0x0F,0x07,0x00,0x00, // 0x37 + 0x36,0x7F,0x49,0x49,0x7F,0x36,0x00,0x00, // 0x38 + 0x06,0x4F,0x49,0x69,0x3F,0x1E,0x00,0x00, // 0x39 + 0x00,0x00,0x6C,0x6C,0x00,0x00,0x00,0x00, // 0x3A + 0x00,0xA0,0xEC,0x6C,0x00,0x00,0x00,0x00, // 0x3B + 0x08,0x1C,0x36,0x63,0x41,0x00,0x00,0x00, // 0x3C + 0x14,0x14,0x14,0x14,0x14,0x14,0x00,0x00, // 0x3D + 0x00,0x41,0x63,0x36,0x1C,0x08,0x00,0x00, // 0x3E + 0x02,0x03,0x51,0x59,0x0F,0x06,0x00,0x00, // 0x3F + 0x3E,0x7F,0x41,0x5D,0x5D,0x1F,0x1E,0x00, // 0x40 + 0x7C,0x7E,0x13,0x13,0x7E,0x7C,0x00,0x00, // 0x41 + 0x41,0x7F,0x7F,0x49,0x49,0x7F,0x36,0x00, // 0x42 + 0x1C,0x3E,0x63,0x41,0x41,0x63,0x22,0x00, // 0x43 + 0x41,0x7F,0x7F,0x41,0x63,0x7F,0x1C,0x00, // 0x44 + 0x41,0x7F,0x7F,0x49,0x5D,0x41,0x63,0x00, // 0x45 + 0x41,0x7F,0x7F,0x49,0x1D,0x01,0x03,0x00, // 0x46 + 0x1C,0x3E,0x63,0x41,0x51,0x73,0x72,0x00, // 0x47 + 0x7F,0x7F,0x08,0x08,0x7F,0x7F,0x00,0x00, // 0x48 + 0x00,0x41,0x7F,0x7F,0x41,0x00,0x00,0x00, // 0x49 + 0x30,0x70,0x40,0x41,0x7F,0x3F,0x01,0x00, // 0x4A + 0x41,0x7F,0x7F,0x08,0x1C,0x77,0x63,0x00, // 0x4B + 0x41,0x7F,0x7F,0x41,0x40,0x60,0x70,0x00, // 0x4C + 0x7F,0x7F,0x06,0x0C,0x06,0x7F,0x7F,0x00, // 0x4D + 0x7F,0x7F,0x06,0x0C,0x18,0x7F,0x7F,0x00, // 0x4E + 0x1C,0x3E,0x63,0x41,0x63,0x3E,0x1C,0x00, // 0x4F + 0x41,0x7F,0x7F,0x49,0x09,0x0F,0x06,0x00, // 0x50 + 0x1E,0x3F,0x21,0x71,0x7F,0x5E,0x00,0x00, // 0x51 + 0x41,0x7F,0x7F,0x19,0x39,0x6F,0x46,0x00, // 0x52 + 0x26,0x67,0x4D,0x59,0x7B,0x32,0x00,0x00, // 0x53 + 0x03,0x41,0x7F,0x7F,0x41,0x03,0x00,0x00, // 0x54 + 0x7F,0x7F,0x40,0x40,0x7F,0x7F,0x00,0x00, // 0x55 + 0x1F,0x3F,0x60,0x60,0x3F,0x1F,0x00,0x00, // 0x56 + 0x7F,0x7F,0x30,0x18,0x30,0x7F,0x7F,0x00, // 0x57 + 0x63,0x77,0x1C,0x08,0x1C,0x77,0x63,0x00, // 0x58 + 0x07,0x4F,0x78,0x78,0x4F,0x07,0x00,0x00, // 0x59 + 0x67,0x73,0x59,0x4D,0x47,0x63,0x71,0x00, // 0x5A + 0x00,0x7F,0x7F,0x41,0x41,0x00,0x00,0x00, // 0x5B + 0x01,0x03,0x06,0x0C,0x18,0x30,0x60,0x00, // 0x5C + 0x00,0x41,0x41,0x7F,0x7F,0x00,0x00,0x00, // 0x5D + 0x08,0x0C,0x06,0x03,0x06,0x0C,0x08,0x00, // 0x5E + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80, // 0x5F + 0x00,0x00,0x03,0x07,0x04,0x00,0x00,0x00, // 0x60 + 0x20,0x74,0x54,0x54,0x3C,0x78,0x40,0x00, // 0x61 + 0x41,0x3F,0x7F,0x44,0x44,0x7C,0x38,0x00, // 0x62 + 0x38,0x7C,0x44,0x44,0x6C,0x28,0x00,0x00, // 0x63 + 0x30,0x78,0x48,0x49,0x3F,0x7F,0x40,0x00, // 0x64 + 0x38,0x7C,0x54,0x54,0x5C,0x18,0x00,0x00, // 0x65 + 0x48,0x7E,0x7F,0x49,0x03,0x02,0x00,0x00, // 0x66 + 0x98,0xBC,0xA4,0xA4,0xF8,0x7C,0x04,0x00, // 0x67 + 0x41,0x7F,0x7F,0x08,0x04,0x7C,0x78,0x00, // 0x68 + 0x00,0x44,0x7D,0x7D,0x40,0x00,0x00,0x00, // 0x69 + 0x40,0xC4,0x84,0xFD,0x7D,0x00,0x00,0x00, // 0x6A + 0x41,0x7F,0x7F,0x10,0x38,0x6C,0x44,0x00, // 0x6B + 0x00,0x41,0x7F,0x7F,0x40,0x00,0x00,0x00, // 0x6C + 0x7C,0x7C,0x0C,0x18,0x0C,0x7C,0x78,0x00, // 0x6D + 0x7C,0x7C,0x04,0x04,0x7C,0x78,0x00,0x00, // 0x6E + 0x38,0x7C,0x44,0x44,0x7C,0x38,0x00,0x00, // 0x6F + 0x84,0xFC,0xF8,0xA4,0x24,0x3C,0x18,0x00, // 0x70 + 0x18,0x3C,0x24,0xA4,0xF8,0xFC,0x84,0x00, // 0x71 + 0x44,0x7C,0x78,0x44,0x1C,0x18,0x00,0x00, // 0x72 + 0x48,0x5C,0x54,0x54,0x74,0x24,0x00,0x00, // 0x73 + 0x00,0x04,0x3E,0x7F,0x44,0x24,0x00,0x00, // 0x74 + 0x3C,0x7C,0x40,0x40,0x3C,0x7C,0x40,0x00, // 0x75 + 0x1C,0x3C,0x60,0x60,0x3C,0x1C,0x00,0x00, // 0x76 + 0x3C,0x7C,0x60,0x30,0x60,0x7C,0x3C,0x00, // 0x77 + 0x44,0x6C,0x38,0x10,0x38,0x6C,0x44,0x00, // 0x78 + 0x9C,0xBC,0xA0,0xA0,0xFC,0x7C,0x00,0x00, // 0x79 + 0x4C,0x64,0x74,0x5C,0x4C,0x64,0x00,0x00, // 0x7A + 0x08,0x08,0x3E,0x77,0x41,0x41,0x00,0x00, // 0x7B + 0x00,0x00,0x00,0x77,0x77,0x00,0x00,0x00, // 0x7C + 0x41,0x41,0x77,0x3E,0x08,0x08,0x00,0x00, // 0x7D + 0x02,0x03,0x01,0x03,0x02,0x03,0x01,0x00, // 0x7E + 0x78,0x7C,0x46,0x43,0x46,0x7C,0x78,0x00}; // 0x7F + +#define FONT_W 8 +#define FONT_H 2 +#define FONT_STRETCHV 1 +#define FONT_STRETCHH 0 +*/ + +static const uint8_t ssd1306_init_sequence [] PROGMEM = { // Initialization Sequence +// 0xAE, // Display OFF (sleep mode) + 0x20, 0b10, // Set Memory Addressing Mode + // 00=Horizontal Addressing Mode; 01=Vertical Addressing Mode; + // 10=Page Addressing Mode (RESET); 11=Invalid +// 0xB0, // Set Page Start Address for Page Addressing Mode, 0-7 + 0xC8, // Set COM Output Scan Direction. Flip Veritically. +// 0x00, // Set low nibble of column address +// 0x10, // Set high nibble of column address + 0x40, // Set display start line address + 0x81, /*32*/ 0x7F, // Set contrast control register + 0xA1, // Set Segment Re-map. A0=column 0 mapped to SEG0; A1=column 127 mapped to SEG0. Flip Horizontally + 0xA6, // Set display mode. A6=Normal; A7=Inverse + 0xA8, 0x1F, // Set multiplex ratio(1 to 64) + 0xA4, // Output RAM to Display + // 0xA4=Output follows RAM content; 0xA5,Output ignores RAM content + 0xD3, 0x00, // Set display offset. 00 = no offset + 0xD5, 0x80, // --set display clock divide ratio/oscillator frequency + 0xD9, 0xF1, // 0xF1=brighter //0x22, // Set pre-charge period + 0xDA, 0x02, // Set com pins hardware configuration +// 0xDB, 0x40, //0x20, // --set vcomh 0x20 = 0.77xVcc + 0x8D, 0x14, // Set DC-DC enable + 0xAF, // Display ON +}; + +class SSD1306Device: public Print { +public: + #define SSD1306_ADDR 0x3C // Slave address + #define SSD1306_PAGES 4 + #define SSD1306_COMMAND 0x00 + #define SSD1306_DATA 0x40 + uint8_t oledX = 0, oledY = 0; + uint8_t renderingFrame = 0xB0; + bool wrap = false; + + void begin(uint8_t cols, uint8_t rows, uint8_t charsize = 0){ + Wire.begin(); + Wire.beginTransmission(SSD1306_ADDR); Wire.write(SSD1306_COMMAND); + for (uint8_t i = 0; i < sizeof(ssd1306_init_sequence); i++) { + Wire.write(pgm_read_byte(&ssd1306_init_sequence[i])); + } + Wire.endTransmission(); + delayMicroseconds(100); + } + void noCursor(){} + void cursor(){} + void noDisplay(){} + void createChar(uint8_t l, uint8_t glyph[]){} + + void _setCursor(uint8_t x, uint8_t y) { oledX = x; oledY = y; + Wire.beginTransmission(SSD1306_ADDR); Wire.write(SSD1306_COMMAND); + Wire.write(renderingFrame | (oledY & 0x07)); + Wire.write(0x10 | ((oledX & 0xf0) >> 4)); + Wire.write(oledX & 0x0f); + Wire.endTransmission(); + } + void setCursor(uint8_t x, uint8_t y) { _setCursor(x * FONT_W, y * FONT_H); } + + void newLine() { + oledY+=FONT_H; + if (oledY > SSD1306_PAGES - FONT_H) { + oledY = SSD1306_PAGES - FONT_H; + } + setCursor(0, oledY); + } + + size_t write(byte c) { + if((c == '\n') || (oledX > ((uint8_t)128 - FONT_W))) { + if(wrap) newLine(); + return 1; + } + + uint16_t offset = ((uint16_t)c - ' ') * FONT_W/(FONT_STRETCHH+1) * FONT_H; + uint8_t line = FONT_H; + do + { + if(FONT_STRETCHV) offset = ((uint16_t)c - ' ') * FONT_W/(FONT_STRETCHH+1) * FONT_H/(2*FONT_STRETCHV); + Wire.beginTransmission(SSD1306_ADDR); Wire.write(SSD1306_DATA); + for (uint8_t i = 0; i < (FONT_W/(FONT_STRETCHH+1)); i++) { + uint8_t b = pgm_read_byte(&(font[offset++])); + if(FONT_STRETCHV){ + uint8_t b2 = 0; + if(line > 1) for(int i = 0; i!=4; i++) b2 |=/* ! */(b & (1< 1) { + _setCursor(oledX, oledY + 1); + } + else { + _setCursor(oledX + FONT_W, oledY - (FONT_H - 1)); + } + } + } + while (--line); + return 1; + } + + void bitmap(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t bitmap[]) { + uint16_t j = 0; + for (uint8_t y = y0; y < y1; y++) { + _setCursor(x0, y); + Wire.beginTransmission(SSD1306_ADDR); Wire.write(SSD1306_DATA); + for (uint8_t x = x0; x < x1; x++) { + Wire.write(pgm_read_byte(&bitmap[j++])); + } + Wire.endTransmission(); + } + setCursor(0, 0); + } +}; +//SSD1306Device lcd; LCD lcd; //#include //LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7); @@ -269,15 +756,15 @@ public: inline void FAST freq_calc_fast(int16_t df) // note: relies on cached variables: _msb128, _msa128min512, _div, _fout, fxtal { - #define _MSC 0x80000 //0x80000: 98% CPU load 0xFFFFF: 114% CPU load - uint32_t msb128 = _msb128 + ((int64_t)(_div * (int32_t)df) * _MSC * 128) / fxtal; + //#define _MSC 0x80000 //0x80000: 98% CPU load 0xFFFFF: 114% CPU load + //uint32_t msb128 = _msb128 + ((int64_t)(_div * (int32_t)df) * _MSC * 128) / fxtal; - //#define _MSC 0xFFFFF // Old algorithm 114% CPU load + //#define _MSC 0xFFFFF // Old algorithm 114% CPU load, shortcut for a fixed fxtal=27e6 //register uint32_t xmsb = (_div * (_fout + (int32_t)df)) % fxtal; // xmsb = msb * fxtal/(128 * _MSC); //uint32_t msb128 = xmsb * 5*(32/32) - (xmsb/32); // msb128 = xmsb * 159/32, where 159/32 = 128 * 0xFFFFF / fxtal; fxtal=27e6 - //#define _MSC (27004800/128) // 114% CPU load perfect alignment - //uint32_t msb128 = (_div * (_fout + (int32_t)df)) % fxtal; + #define _MSC (27004800/128) // 114% CPU load perfect alignment + uint32_t msb128 = (_div * (_fout + (int32_t)df)) % fxtal; uint32_t msp1 = _msa128min512 + msb128 / _MSC; // = 128 * _msa + msb128 / _MSC - 512; uint32_t msp2 = msb128 % _MSC; // = msb128 - msb128/_MSC * _MSC; @@ -708,9 +1195,9 @@ volatile int8_t volume = 8; void dsp_tx() { // jitter dependent things first ADCSRA |= (1 << ADSC); // start next ADC conversion (trigger ADC interrupt if ADIE flag is set) - OCR1BL = amp; // submit amplitude to PWM register (actually this is done in advance (about 140us) of phase-change, so that phase-delays in key-shaping circuit filter can settle) + //OCR1BL = amp; // submit amplitude to PWM register (actually this is done in advance (about 140us) of phase-change, so that phase-delays in key-shaping circuit filter can settle) si5351.SendPLLBRegisterBulk(); // submit frequency registers to SI5351 over 731kbit/s I2C (transfer takes 64/731 = 88us, then PLL-loopfilter probably needs 50us to stabalize) - //OCR1BL = amp; // submit amplitude to PWM register (takes about 1/32125 = 31us+/-31us to propagate) -> amplitude-phase-alignment error is about 30-50us + OCR1BL = amp; // submit amplitude to PWM register (takes about 1/32125 = 31us+/-31us to propagate) -> amplitude-phase-alignment error is about 30-50us int16_t adc = ADC - 512; // current ADC sample 10-bits analog input, NOTE: first ADCL, then ADCH int16_t df = ssb(adc >> MIC_ATTEN); // convert analog input into phase-shifts (carrier out by periodic frequency shifts) si5351.freq_calc_fast(df); // calculate SI5351 registers based on frequency shift and carrier frequency @@ -1001,10 +1488,8 @@ inline int16_t slow_dsp(int16_t ac) if(agc) ac = process_agc(ac); ac = ac >> (16-volume); if(nr) ac = process_nr(ac); - if(filt) ac = filt_var(ac); - if(mode == CW){ - if(filt) ac = ac << 2; - + if(filt) ac = filt_var(ac) << 2; + if(mode == CW){ if(cwdec){ // CW decoder enabled? char ch = cw(ac >> 0); if(ch){ @@ -1386,7 +1871,7 @@ char blanks[] = " "; #define lcd_blanks() lcd.print(blanks); #define N_FONTS 8 -const byte font[N_FONTS][8] PROGMEM = { +const byte fonts[N_FONTS][8] PROGMEM = { { 0b01000, // 1; logo 0b00100, 0b01010, @@ -1873,8 +2358,8 @@ void setup() lcd.begin(16, 2); // Init LCD for(i = 0; i != N_FONTS; i++){ // Init fonts - pgm_cache_item(font[i], 8); - lcd.createChar(0x01 + i, /*font[i]*/_item); + pgm_cache_item(fonts[i], 8); + lcd.createChar(0x01 + i, /*fonts[i]*/_item); } // Test if QCX has DSP/SDR capability: SIDETONE output disconnected from AUDIO2 @@ -2107,8 +2592,8 @@ void loop() for(; digitalRead(BUTTONS);){ // until released, or encoder is turned while longpress if(encoder_val && event == PL){ event = PT; break; } wdt_reset(); - } - event |= (v < 862) ? BL : (v < 1023) ? BR : BE; // determine which button pressed based on threshold levels + } // Max. voltages at ADC3 for buttons L,R,E: 3.76V;4.55V;5V, thresholds are in center + event |= (v < (4.2 * 1024.0 / 5.0)) ? BL : (v < (4.8 * 1024.0 / 5.0)) ? BR : BE; // determine which button pressed based on threshold levels } else { // hack: fast forward handling event = (event&0xf0) | ((encoder_val) ? PT : PL); // only alternate bewteen push-long/turn when applicable } @@ -2390,13 +2875,21 @@ faster RX-TX switch to support CW clock qcx API demo code scan -si5351 simplification aka https://groups.io/g/BITX20/files/KE7ER/si5351bx_0_0.ino unwanted VOX feedback in DSP mode move last bit of arrays into flash? https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_rom_array.html remove floats +Multiple ADC conversion and avg in TX path +u-law in RX path: http://dystopiancode.blogspot.com/2012/02/pcm-law-and-u-law-companding-algorithms.html +Arduino library? +1. RX bias offset correction by measurement avg, 2. charge decoupling cap. by resetting to 0V and setting 5V for a certain amount of (charge) time Analyse assembly: /home/guido/Downloads/arduino-1.8.10/hardware/tools/avr/bin/avr-g++ -S -g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -Wno-error=narrowing -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10810 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -I/home/guido/Downloads/arduino-1.8.10/hardware/arduino/avr/cores/arduino -I/home/guido/Downloads/arduino-1.8.10/hardware/arduino/avr/variants/standard /tmp/arduino_build_483134/sketch/QCX-SSB.ino.cpp -o /tmp/arduino_build_483134/sketch/QCX-SSB.ino.cpp.txt +Rewire/code I/Q clk pins so that a Div/1 and Div/2 scheme is used instead of 0 and 90 degrees phase shift +10,11,13,12 10,11,12,13 (pin) +Q- I+ Q+ I- Q- I+ Q+ I- +90 deg.shift div/2@S1(pin2) + */