initial
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_i2c.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
|
||||
void ssd1306_i2cInitEx(int8_t scl, int8_t sda, int8_t sa)
|
||||
{
|
||||
#if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
|
||||
ssd1306_platform_i2cConfig_t cfg;
|
||||
cfg.scl = scl;
|
||||
cfg.sda = sda;
|
||||
ssd1306_platform_i2cInit(-1, sa, &cfg);
|
||||
#elif defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
|
||||
ssd1306_i2cConfigure_Twi(0);
|
||||
ssd1306_i2cInit_Twi(sa);
|
||||
#elif defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
|
||||
ssd1306_i2cInit_Embedded(scl, sda, sa);
|
||||
#else
|
||||
#warning "ssd1306 library: no i2c support for the target platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void ssd1306_i2cInitEx2(int8_t busId, int8_t scl, int8_t sda, int8_t sa)
|
||||
{
|
||||
#if defined(CONFIG_PLATFORM_I2C_AVAILABLE) && defined(CONFIG_PLATFORM_I2C_ENABLE)
|
||||
ssd1306_platform_i2cConfig_t cfg;
|
||||
cfg.scl = scl;
|
||||
cfg.sda = sda;
|
||||
ssd1306_platform_i2cInit(busId, sa, &cfg);
|
||||
#elif defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
|
||||
ssd1306_i2cConfigure_Twi(0);
|
||||
ssd1306_i2cInit_Twi(sa);
|
||||
#elif defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
|
||||
ssd1306_i2cInit_Embedded(scl, sda, sa);
|
||||
#else
|
||||
#warning "ssd1306 library: no i2c support for the target platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void ssd1306_i2cInit()
|
||||
{
|
||||
ssd1306_i2cInitEx(-1, -1, SSD1306_SA);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file ssd1306_i2c.h SSD1306 i2c communication functions
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SSD1306_I2C_H_
|
||||
#define _SSD1306_I2C_H_
|
||||
|
||||
#include "ssd1306_i2c_conf.h"
|
||||
#include "ssd1306_i2c_embedded.h"
|
||||
#include "ssd1306_i2c_twi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Inits display interface to use i2c bus.
|
||||
* The function automatically selects available type of i2c implementation
|
||||
* 1. Wire library
|
||||
* 2. sw i2c implementation
|
||||
* In case of using Wire library this function calls Wire.begin() and
|
||||
* sets speed to fast i2c (400kHz). If you prefer to use your own Wire settings
|
||||
* or avoid reinitializing of Wire library, please use ssd1306_i2cInit_Wire().
|
||||
* If you want to use embedded i2c (if it is supported), use ssd1306_i2cInit_Embedded().
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_i2cInit(void);
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Inits display interface to use i2c bus.
|
||||
* The function automatically selects available type of i2c implementation
|
||||
* 1. Wire library
|
||||
* 2. sw i2c implementation
|
||||
* In case of using Wire library this function calls Wire.begin() and
|
||||
* sets speed to fast i2c (400kHz). If you prefer to use your own Wire settings
|
||||
* or avoid reinitializing of Wire library, please use ssd1306_i2cInit_Wire().
|
||||
* If you want to use embedded i2c (if it is supported), use ssd1306_i2cInit_Embedded().
|
||||
*
|
||||
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
|
||||
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
|
||||
* @param sa - i2c address of lcd display. Use 0 to leave default
|
||||
*
|
||||
* @note scl and sda parameters depend on used hardware. For many hardware boards these
|
||||
* parameters do not have any effect. ESP8266 allows to specify these parameters
|
||||
*
|
||||
* @note scl and sda for Linux systems should be the same, and should contain i2c bus id.
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_i2cInitEx(int8_t scl, int8_t sda, int8_t sa);
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Inits display interface to use i2c bus.
|
||||
* The function automatically selects available type of i2c implementation
|
||||
* 1. Wire library
|
||||
* 2. sw i2c implementation
|
||||
* In case of using Wire library this function calls Wire.begin() and
|
||||
* sets speed to fast i2c (400kHz). If you prefer to use your own Wire settings
|
||||
* or avoid reinitializing of Wire library, please use ssd1306_i2cInit_Wire().
|
||||
* If you want to use embedded i2c (if it is supported), use ssd1306_i2cInit_Embedded().
|
||||
*
|
||||
* @param busId - number of i2c bus if there are multiple hw blocks avialable.
|
||||
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
|
||||
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
|
||||
* @param sa - i2c address of lcd display. Use 0 to leave default
|
||||
*
|
||||
* @note scl and sda parameters depend on used hardware. For many hardware boards these
|
||||
* parameters do not have any effect. ESP8266 allows to specify these parameters
|
||||
*
|
||||
* @note scl and sda for Linux systems should be the same, and should contain i2c bus id.
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_i2cInitEx2(int8_t busId, int8_t scl, int8_t sda, int8_t sa);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // _SSD1306_I2C_H_
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_i2c_conf.h SSD1306 library basic i2c definitions
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_I2C_CONF_H_
|
||||
#define _SSD1306_I2C_CONF_H_
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SSD1306_SA
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* SSD1306_SA defines default i2c address of LCD display. Please, check your device.
|
||||
* If you LCD device has different address, you can set different one via
|
||||
* ssd1306_i2cInit_Wire() or ssd1306_i2cInit_Embedded() functions.
|
||||
* Write command will be SSD1306_SA<<1 and read will be SSD1306_SA<<1 | 1
|
||||
*/
|
||||
#define SSD1306_SA 0x3C // Slave address
|
||||
#endif
|
||||
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
#ifndef SSD1306_SCL
|
||||
#define SSD1306_SCL 3 ///< SCL, Pin 3 on SSD1306 Board
|
||||
#endif
|
||||
#ifndef SSD1306_SDA
|
||||
#define SSD1306_SDA 4 ///< SDA, Pin 4 on SSD1306 Board
|
||||
#endif
|
||||
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||
#ifndef SSD1306_SCL
|
||||
#define SSD1306_SCL 4 ///< SCL, Pin 4 - physical pin 9 of Attiny84
|
||||
#endif
|
||||
#ifndef SSD1306_SDA
|
||||
#define SSD1306_SDA 6 ///< SDA, Pin 6 - physical pin 7 of Attiny84
|
||||
#endif
|
||||
#else
|
||||
#ifndef SSD1306_SCL
|
||||
#define SSD1306_SCL 5 // SCL, Pin A5 on SSD1306 Board
|
||||
#endif
|
||||
#ifndef SSD1306_SDA
|
||||
#define SSD1306_SDA 4 // SDA, Pin A4 on SSD1306 Board
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_i2c_embedded.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "ssd1306_i2c.h"
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
|
||||
|
||||
#include <util/delay_basic.h>
|
||||
|
||||
/**
|
||||
* Port registers, containing pins, which SSD1306 display is connected to.
|
||||
* For ATtiny controllers it is standard PORTB
|
||||
* For ATmega328p, it is PORTC, which corresponds to Analog inputs/outputs
|
||||
*/
|
||||
|
||||
static uint8_t s_scl = (1<<SSD1306_SCL);
|
||||
static uint8_t s_sda = (1<<SSD1306_SDA);
|
||||
static uint8_t s_sa = SSD1306_SA;
|
||||
|
||||
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
// at 8Mhz each command takes ~ 0.125us
|
||||
#define DDR_REG DDRB
|
||||
#define PORT_REG PORTB
|
||||
#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||
// For AttinyX4 controllers
|
||||
// at 8Mhz each command takes ~ 0.125us
|
||||
#define DDR_REG DDRA
|
||||
#define PORT_REG PORTA
|
||||
#else // For Atmega
|
||||
// at 16Mhz each command takes ~ 0.0625us
|
||||
#define DDR_REG DDRC
|
||||
#define PORT_REG PORTC
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef F_CPU
|
||||
#warning "F_CPU is not defined, there can be I2C issues"
|
||||
#define F_CPU 8000000
|
||||
#endif
|
||||
#define CPU_CYCLE_NS (1000000000/F_CPU)
|
||||
|
||||
#define DELAY_LOOP_CYCLES 4
|
||||
#define ssd1306_delay(x) _delay_loop_2(x)
|
||||
|
||||
/**
|
||||
* Section, which defines I2C timings for SSD1306 display from datasheet
|
||||
*/
|
||||
#define SSD1306_I2C_START_STOP_DELAY 600
|
||||
#define SSD1306_I2C_RISE_TIME 300
|
||||
#define SSD1306_I2C_FALL_TIME 300
|
||||
#define SSD1306_I2C_DATA_HOLD_TIME 300
|
||||
#define SSD1306_I2C_IDLE_TIME 1300
|
||||
#define SSD1306_I2C_CLOCK 2500
|
||||
|
||||
|
||||
#define I2C_START_STOP_DELAY ((SSD1306_I2C_START_STOP_DELAY/CPU_CYCLE_NS + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
|
||||
|
||||
#define I2C_RISE_TIME ((SSD1306_I2C_RISE_TIME/CPU_CYCLE_NS)/DELAY_LOOP_CYCLES)
|
||||
|
||||
#define I2C_DATA_HOLD_TIME ((SSD1306_I2C_DATA_HOLD_TIME/CPU_CYCLE_NS + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
|
||||
|
||||
#define I2C_IDLE_TIME (((SSD1306_I2C_IDLE_TIME/CPU_CYCLE_NS) + DELAY_LOOP_CYCLES/2)/DELAY_LOOP_CYCLES)
|
||||
|
||||
#define I2C_HALF_CLOCK (((SSD1306_I2C_CLOCK - SSD1306_I2C_FALL_TIME - SSD1306_I2C_RISE_TIME - SSD1306_I2C_FALL_TIME)/CPU_CYCLE_NS/2 \
|
||||
)/DELAY_LOOP_CYCLES)
|
||||
|
||||
|
||||
/* I2C HIGH = PORT as INPUT(0) and PULL-UP ENABLE (1) */
|
||||
//#define DIGITAL_WRITE_HIGH(DREG, PREG, BIT) { DREG &= ~(1 << BIT); PREG |= (1 << BIT); }
|
||||
#define DIGITAL_WRITE_HIGH(DREG, PREG, BIT) { DREG &= ~BIT; PREG |= BIT; }
|
||||
|
||||
/* I2C LOW = PORT as OUTPUT(1) and OUTPUT LOW (0) */
|
||||
//#define DIGITAL_WRITE_LOW(DREG, PREG, BIT) { DREG |= (1 << BIT); PREG &= ~(1 << BIT); }
|
||||
#define DIGITAL_WRITE_LOW(DREG, PREG, BIT) { DREG |= BIT; PREG &= ~BIT; }
|
||||
|
||||
static uint8_t oldSREG;
|
||||
static uint8_t interruptsOff = 0;
|
||||
|
||||
/**
|
||||
* Inputs: SCL is LOW, SDA is has no meaning
|
||||
* Outputs: SCL is LOW
|
||||
*/
|
||||
static void ssd1306_i2cSendByte_Embedded(uint8_t data)
|
||||
{
|
||||
uint8_t i;
|
||||
for(i=8; i>0; i--)
|
||||
{
|
||||
if(data & 0x80)
|
||||
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda)
|
||||
else
|
||||
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda);
|
||||
data<<=1;
|
||||
ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
|
||||
|
||||
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl);
|
||||
ssd1306_delay(I2C_HALF_CLOCK);
|
||||
|
||||
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl);
|
||||
ssd1306_delay(I2C_HALF_CLOCK);
|
||||
}
|
||||
// generating confirmation impulse
|
||||
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda);
|
||||
ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
|
||||
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl);
|
||||
ssd1306_delay(I2C_HALF_CLOCK);
|
||||
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl);
|
||||
ssd1306_delay(I2C_HALF_CLOCK);
|
||||
}
|
||||
|
||||
static void ssd1306_i2cSendBytes_Embedded(const uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
ssd1306_i2cSendByte_Embedded(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SCL remains HIGH on EXIT, Low SDA means start transmission
|
||||
*/
|
||||
static void ssd1306_i2cStart_Embedded(void)
|
||||
{
|
||||
oldSREG = SREG;
|
||||
cli();
|
||||
interruptsOff = 1;
|
||||
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda); // Set to LOW
|
||||
ssd1306_delay(I2C_START_STOP_DELAY);
|
||||
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_scl); // Set to LOW
|
||||
ssd1306_delay(I2C_HALF_CLOCK);
|
||||
ssd1306_i2cSendByte_Embedded((s_sa << 1) | 0);
|
||||
}
|
||||
|
||||
static void ssd1306_i2cStop_Embedded(void)
|
||||
{
|
||||
DIGITAL_WRITE_LOW(DDR_REG, PORT_REG, s_sda); // Set to LOW
|
||||
ssd1306_delay(I2C_RISE_TIME); // Fall time is the same as rise time
|
||||
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_scl); // Set to HIGH
|
||||
ssd1306_delay(I2C_START_STOP_DELAY);
|
||||
DIGITAL_WRITE_HIGH(DDR_REG, PORT_REG, s_sda); // Set to HIGH
|
||||
ssd1306_delay(I2C_IDLE_TIME);
|
||||
if (interruptsOff)
|
||||
{
|
||||
SREG = oldSREG;
|
||||
interruptsOff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssd1306_i2cClose_Embedded()
|
||||
{
|
||||
}
|
||||
|
||||
void ssd1306_i2cInit_Embedded(int8_t scl, int8_t sda, uint8_t sa)
|
||||
{
|
||||
if (scl>=0) s_scl = (1<<scl);
|
||||
if (sda>=0) s_sda = (1<<sda);
|
||||
if (sa) s_sa = sa;
|
||||
ssd1306_intf.spi = 0;
|
||||
ssd1306_intf.start = ssd1306_i2cStart_Embedded;
|
||||
ssd1306_intf.stop = ssd1306_i2cStop_Embedded;
|
||||
ssd1306_intf.send = ssd1306_i2cSendByte_Embedded;
|
||||
ssd1306_intf.send_buffer = ssd1306_i2cSendBytes_Embedded;
|
||||
ssd1306_intf.close = ssd1306_i2cClose_Embedded;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_i2c_embedded.h embedded SSD1306 i2c communication functions
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_I2C_EMBEDDED_H_
|
||||
#define _SSD1306_I2C_EMBEDDED_H_
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
#include "ssd1306_i2c_conf.h"
|
||||
|
||||
#if defined(CONFIG_SOFTWARE_I2C_AVAILABLE) && defined(CONFIG_SOFTWARE_I2C_ENABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Initializes software implementation of i2c.
|
||||
* If you do not know i2c parameters, try ssd1306_i2cInit_Embedded(0,0,0).
|
||||
* @warning the function disables interrupts.
|
||||
* @param scl - i2c clock pin. Use -1 if you don't need to change default pin number
|
||||
* @param sda - i2c data pin. Use -1 if you don't need to change default pin number
|
||||
* @param sa - i2c address of lcd display. Use 0 to leave default
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_i2cInit_Embedded(int8_t scl, int8_t sda, uint8_t sa);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SSD1306_I2C_EMBEDDED_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_i2c_twi.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "ssd1306_i2c.h"
|
||||
|
||||
#if defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <util/twi.h>
|
||||
|
||||
/* Max i2c frequency, supported by OLED controllers */
|
||||
#define SSD1306_TWI_FREQ 400000
|
||||
#define MAX_RETRIES 64
|
||||
|
||||
static uint8_t s_sa = SSD1306_SA;
|
||||
|
||||
static uint8_t ssd1306_twi_start(void)
|
||||
{
|
||||
uint8_t twst;
|
||||
uint8_t iters = MAX_RETRIES;
|
||||
do
|
||||
{
|
||||
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
|
||||
while ( (TWCR & (1<<TWINT)) == 0 );
|
||||
twst = TWSR & 0xF8;
|
||||
if (!--iters)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (twst == TW_MT_ARB_LOST);
|
||||
if ((twst != TW_START) && (twst != TW_REP_START))
|
||||
{
|
||||
return twst;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t ssd1306_twi_send(uint8_t data)
|
||||
{
|
||||
uint8_t twsr;
|
||||
uint8_t iters = MAX_RETRIES;
|
||||
do
|
||||
{
|
||||
TWDR = data;
|
||||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||||
while ( (TWCR & (1<<TWINT)) == 0 );
|
||||
twsr = TWSR & 0xF8;
|
||||
if ((twsr == TW_MT_SLA_ACK) || (twsr == TW_MT_DATA_ACK))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (twsr == TW_MT_ARB_LOST)
|
||||
{
|
||||
return twsr;
|
||||
}
|
||||
iters++;
|
||||
if (!--iters)
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (twsr != TW_MT_ARB_LOST);
|
||||
return twsr;
|
||||
}
|
||||
|
||||
|
||||
static void ssd1306_twi_stop(void)
|
||||
{
|
||||
TWCR = (1<<TWEN) | (1<<TWSTO) | (1<<TWINT);
|
||||
}
|
||||
|
||||
static void ssd1306_i2cStart_Twi(void)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (ssd1306_twi_start() != 0)
|
||||
{
|
||||
/* Some serious error happened, but we don't care. Our API functions have void type */
|
||||
return;
|
||||
}
|
||||
} while (ssd1306_twi_send(s_sa << 1) == TW_MT_ARB_LOST);
|
||||
}
|
||||
|
||||
static void ssd1306_i2cStop_Twi(void)
|
||||
{
|
||||
ssd1306_twi_stop();
|
||||
}
|
||||
|
||||
void ssd1306_i2cConfigure_Twi(uint8_t arg)
|
||||
{
|
||||
#if defined(__AVR_ATmega328P__)
|
||||
/* Enable internal pull-ups */
|
||||
DDRC &= ~(1<<PINC4); PORTC |= (1<<PINC4);
|
||||
DDRC &= ~(1<<PINC5); PORTC |= (1<<PINC5);
|
||||
#endif
|
||||
#if defined(TWPS0)
|
||||
TWSR = 0;
|
||||
#endif
|
||||
TWBR = ((F_CPU / SSD1306_TWI_FREQ) - 16) / 2 / (1); // Always use prescaler 1 (TWSR 0x00)
|
||||
TWCR = (1 << TWEN) | (1 << TWEA);
|
||||
}
|
||||
|
||||
static void ssd1306_i2cSendByte_Twi(uint8_t data)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if (ssd1306_twi_send(data) != TW_MT_ARB_LOST)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ssd1306_twi_start() != 0)
|
||||
{
|
||||
/* Some serious error happened, but we don't care. Our API functions have void type */
|
||||
break;
|
||||
}
|
||||
if (ssd1306_twi_send(s_sa << 1) != TW_MT_ARB_LOST)
|
||||
{
|
||||
/* Some serious error happened, but we don't care. Our API functions have void type */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ssd1306_i2cSendBytes_Twi(const uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
ssd1306_i2cSendByte_Twi(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ssd1306_i2cClose_Twi()
|
||||
{
|
||||
}
|
||||
|
||||
void ssd1306_i2cInit_Twi(uint8_t sa)
|
||||
{
|
||||
if (sa) s_sa = sa;
|
||||
ssd1306_intf.spi = 0;
|
||||
ssd1306_intf.start = ssd1306_i2cStart_Twi;
|
||||
ssd1306_intf.stop = ssd1306_i2cStop_Twi;
|
||||
ssd1306_intf.send = ssd1306_i2cSendByte_Twi;
|
||||
ssd1306_intf.send_buffer = ssd1306_i2cSendBytes_Twi;
|
||||
ssd1306_intf.close = ssd1306_i2cClose_Twi;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_i2c_twi.h SSD1306 i2c communication functions for standard AVR TWI interface
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_I2C_TWI_H_
|
||||
#define _SSD1306_I2C_TWI_H_
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
#include "ssd1306_i2c_conf.h"
|
||||
|
||||
#if defined(CONFIG_TWI_I2C_AVAILABLE) && defined(CONFIG_TWI_I2C_ENABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Configures standard TWI AVR module (at 400kHz).
|
||||
* This function is called by ssd1306_i2cInit().
|
||||
* @param arg - has no meaning for now. Should be zero
|
||||
*
|
||||
* @note scl and sda pins depend on used hardware.
|
||||
*/
|
||||
void ssd1306_i2cConfigure_Twi(uint8_t arg);
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Initializes ssd1306 library to use TWI AVR module for i2c.
|
||||
* If you do not know i2c parameters, try ssd1306_i2cInit_Twi(0).
|
||||
* SCL and SDA pins depend on platform.
|
||||
* @param sa - i2c address of lcd display. Use 0 to leave default
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_i2cInit_Twi(uint8_t sa);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SSD1306_I2C_TWI_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "ssd1306_spi.h"
|
||||
#include "ssd1306_spi_avr.h"
|
||||
#include "ssd1306_spi_usi.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
int8_t s_ssd1306_cs = 4;
|
||||
int8_t s_ssd1306_dc = 5;
|
||||
uint32_t s_ssd1306_spi_clock = 8000000;
|
||||
|
||||
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin)
|
||||
{
|
||||
#if defined(CONFIG_AVR_SPI_AVAILABLE) && defined(CONFIG_AVR_SPI_ENABLE)
|
||||
ssd1306_spiInit_avr(cesPin, dcPin);
|
||||
#elif defined(CONFIG_PLATFORM_SPI_AVAILABLE) && defined(CONFIG_PLATFORM_SPI_ENABLE)
|
||||
ssd1306_platform_spiInit(-1, cesPin, dcPin);
|
||||
#elif defined(CONFIG_USI_SPI_AVAILABLE) && defined(CONFIG_USI_SPI_ENABLE)
|
||||
ssd1306_spiInit_Usi(cesPin, dcPin);
|
||||
#else
|
||||
#warning "ssd1306 library: no spi support for the target platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void ssd1306_spiDataMode(uint8_t mode)
|
||||
{
|
||||
if (s_ssd1306_dc)
|
||||
{
|
||||
digitalWrite(s_ssd1306_dc, mode ? HIGH : LOW);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_spi.h SSD1306 spi communication functions
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_SPI_H_
|
||||
#define _SSD1306_SPI_H_
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* chip enable pin to controll lcd display over spi
|
||||
*/
|
||||
extern int8_t s_ssd1306_cs;
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* data/command control pin for spi interface of lcd display
|
||||
*/
|
||||
extern int8_t s_ssd1306_dc;
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
* maximum SPI clock, supported by OLED display
|
||||
*/
|
||||
extern uint32_t s_ssd1306_spi_clock;
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Inits lcd interface to use hardware spi for communication.
|
||||
* The function automatically selects available type of spi implementation
|
||||
* 1. SPI library (ssd1306_spiInit_hw())
|
||||
* @param cesPin - pin, controlling chip enable of LCD
|
||||
* @param dcPin - pin, controlling data/command mode of LCD
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_spiInit(int8_t cesPin, int8_t dcPin);
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Switches spi to data(1) or command(0) mode.
|
||||
* @param mode - 1 data mode
|
||||
* 0 command mode
|
||||
*/
|
||||
void ssd1306_spiDataMode(uint8_t mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // _SSD1306_SPI_H_
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2019, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_spi_avr.h"
|
||||
#include "ssd1306_spi.h"
|
||||
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_AVR_SPI_AVAILABLE) && defined(CONFIG_AVR_SPI_ENABLE)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PORT_SPI PORTB
|
||||
#define DDR_SPI DDRB
|
||||
|
||||
#if defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
||||
#define DD_MISO DDB3
|
||||
#define DD_MOSI DDB2
|
||||
#define DD_SCK DDB1
|
||||
#define DD_SS DDB0
|
||||
#else
|
||||
#define DD_MISO DDB4
|
||||
#define DD_MOSI DDB3
|
||||
#define DD_SCK DDB5
|
||||
#define DD_SS DDB2
|
||||
#endif
|
||||
|
||||
#define SPI_CLOCK_MASK 0x03
|
||||
#define SPI_2XCLOCK_MASK 0x01
|
||||
|
||||
extern uint32_t s_ssd1306_spi_clock;
|
||||
|
||||
static void ssd1306_spiConfigure_avr()
|
||||
{
|
||||
uint8_t clockDiv;
|
||||
uint32_t clockSetting = F_CPU / 2;
|
||||
clockDiv = 0;
|
||||
while ((clockDiv < 6) && (s_ssd1306_spi_clock < clockSetting))
|
||||
{
|
||||
clockSetting /= 2;
|
||||
clockDiv++;
|
||||
}
|
||||
if (clockDiv == 6)
|
||||
{
|
||||
clockDiv = 7;
|
||||
}
|
||||
// Invert the SPI2X bit
|
||||
clockDiv ^= 0x1;
|
||||
|
||||
// SS pin must be HIGH, when enabling MASTER SPI mode
|
||||
// Otherwise, SPI will drop automatically to SLAVE mode
|
||||
DDR_SPI &= ~((1<<DD_SCK)|(1<<DD_SS)|(1<<DD_MOSI));
|
||||
PORT_SPI |= (1<<DD_SS);
|
||||
/* Define the following pins as output */
|
||||
DDR_SPI |= ((1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS));
|
||||
PORT_SPI |= (1<<DD_SS);
|
||||
|
||||
SPCR = (1<<SPE)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|
|
||||
((clockDiv >> 1) & SPI_CLOCK_MASK);
|
||||
SPSR = clockDiv & SPI_2XCLOCK_MASK; // Double Clock Rate
|
||||
// Wait for some time to give SPI HW module to initialize
|
||||
delay(10);
|
||||
}
|
||||
|
||||
static void ssd1306_spiClose_avr()
|
||||
{
|
||||
}
|
||||
|
||||
static void ssd1306_spiStart_avr()
|
||||
{
|
||||
if (s_ssd1306_cs >= 0)
|
||||
{
|
||||
digitalWrite(s_ssd1306_cs,LOW);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssd1306_spiSendByte_avr(uint8_t data)
|
||||
{
|
||||
SPDR = data;
|
||||
asm volatile("nop");
|
||||
while((SPSR & (1<<SPIF))==0);
|
||||
}
|
||||
|
||||
static void ssd1306_spiSendBytes_avr(const uint8_t * buffer, uint16_t size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
SPDR = *buffer;
|
||||
asm volatile("nop"); // to improve speed
|
||||
while((SPSR & (1<<SPIF))==0);
|
||||
SPDR; // read SPI input
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ssd1306_spiStop_avr()
|
||||
{
|
||||
if (ssd1306_lcd.type == LCD_TYPE_PCD8544)
|
||||
{
|
||||
digitalWrite(s_ssd1306_dc, LOW);
|
||||
ssd1306_spiSendByte_avr( 0x00 ); // Send NOP command to allow last data byte to pass (bug in PCD8544?)
|
||||
// ssd1306 E3h is NOP command
|
||||
}
|
||||
if (s_ssd1306_cs >= 0)
|
||||
{
|
||||
digitalWrite(s_ssd1306_cs, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_spiInit_avr(int8_t cesPin, int8_t dcPin)
|
||||
{
|
||||
if (cesPin >=0) pinMode(cesPin, OUTPUT);
|
||||
if (dcPin >= 0) pinMode(dcPin, OUTPUT);
|
||||
if (cesPin) s_ssd1306_cs = cesPin;
|
||||
if (dcPin) s_ssd1306_dc = dcPin;
|
||||
ssd1306_intf.spi = 1;
|
||||
ssd1306_spiConfigure_avr();
|
||||
ssd1306_intf.start = ssd1306_spiStart_avr;
|
||||
ssd1306_intf.stop = ssd1306_spiStop_avr;
|
||||
ssd1306_intf.send = ssd1306_spiSendByte_avr;
|
||||
ssd1306_intf.send_buffer = ssd1306_spiSendBytes_avr;
|
||||
ssd1306_intf.close = ssd1306_spiClose_avr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_spi_avr.h SSD1306 AVR spi communication functions
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_AVR_SPI_H_
|
||||
#define _SSD1306_AVR_SPI_H_
|
||||
|
||||
#include "ssd1306_spi_conf.h"
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AVR_SPI_AVAILABLE) && defined(CONFIG_AVR_SPI_ENABLE)
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Inits lcd interface to use hardware SPI for communication (SPI.h library).
|
||||
* It uses standard MOSI, SCLK pins to send data to LCD.
|
||||
* @param cesPin - pin, controlling chip enable of LCD
|
||||
* @param dcPin - pin, controlling data/command mode of LCD
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_spiInit_avr(int8_t cesPin, int8_t dcPin);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // _SSD1306_AVR_SPI_H_
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_spi_conf.h SSD1306 library basic spi definitions. Only for compatibility
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_SPI_CONF_H_
|
||||
#define _SSD1306_SPI_CONF_H_
|
||||
|
||||
// TODO: Remove this module completely
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_spi_usi.h"
|
||||
#include "ssd1306_spi.h"
|
||||
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_USI_SPI_AVAILABLE) && defined(CONFIG_USI_SPI_ENABLE)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
#define PORT_SPI PORTB
|
||||
#define DDR_SPI DDRB
|
||||
#define DD_DI DDB0
|
||||
#define DD_DO DDB1
|
||||
#define DD_SCK DDB2
|
||||
|
||||
static void ssd1306_spiConfigure_Usi()
|
||||
{
|
||||
DDR_SPI |= (1<<DD_DO); // as output (DO) - data out
|
||||
DDR_SPI |= (1<<DD_SCK); // as output (USISCK) - clock
|
||||
/* DI pin is still used by USI, although ssd1306 library doesn't need it */
|
||||
// DDR_SPI &= ~(1<<DD_DI); // as input (DI) - data in
|
||||
// PORT_SPI|= (1<<DD_DI); // pullup on (DI)
|
||||
}
|
||||
|
||||
static void ssd1306_spiClose_Usi()
|
||||
{
|
||||
}
|
||||
|
||||
static void ssd1306_spiStart_Usi()
|
||||
{
|
||||
if (s_ssd1306_cs >= 0)
|
||||
{
|
||||
digitalWrite(s_ssd1306_cs,LOW);
|
||||
}
|
||||
USICR = (0<<USIWM1) | (1<<USIWM0) |
|
||||
(1<<USICS1) | (0<<USICS0) | (1<<USICLK);
|
||||
}
|
||||
|
||||
static void ssd1306_spiSendByte_Usi(uint8_t data)
|
||||
{
|
||||
USIDR = data;
|
||||
USISR = (1<<USIOIF);
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
while ( (USISR & (1<<USIOIF)) == 0 )
|
||||
{
|
||||
USICR |= (1<<USITC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ssd1306_spiSendBytes_Usi(const uint8_t *buffer, uint16_t size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
USIDR = *buffer;
|
||||
USISR = (1<<USIOIF);
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
{
|
||||
while ( (USISR & (1<<USIOIF)) == 0 )
|
||||
{
|
||||
USICR |= (1<<USITC);
|
||||
}
|
||||
}
|
||||
buffer++;
|
||||
};
|
||||
}
|
||||
|
||||
static void ssd1306_spiStop_Usi()
|
||||
{
|
||||
if (s_ssd1306_cs >= 0)
|
||||
{
|
||||
digitalWrite(s_ssd1306_cs, HIGH);
|
||||
}
|
||||
if (ssd1306_lcd.type == LCD_TYPE_PCD8544)
|
||||
{
|
||||
digitalWrite(s_ssd1306_dc, LOW);
|
||||
ssd1306_spiSendByte_Usi( 0x00 ); // Send NOP command to allow last data byte to pass (bug in PCD8544?)
|
||||
// ssd1306 E3h is NOP command
|
||||
}
|
||||
// USICR &= ~((1<<USIWM1) | (1<<USIWM0));
|
||||
}
|
||||
|
||||
void ssd1306_spiInit_Usi(int8_t cesPin, int8_t dcPin)
|
||||
{
|
||||
if (cesPin >=0)
|
||||
{
|
||||
pinMode(cesPin, OUTPUT);
|
||||
digitalWrite(cesPin, HIGH);
|
||||
}
|
||||
if (dcPin >= 0) pinMode(dcPin, OUTPUT);
|
||||
if ((cesPin >= 0) || (dcPin >= 0))
|
||||
{
|
||||
/* Even if CS pin is not used we need still to set it to value passed to the function */
|
||||
s_ssd1306_cs = cesPin;
|
||||
s_ssd1306_dc = dcPin;
|
||||
}
|
||||
ssd1306_spiConfigure_Usi();
|
||||
ssd1306_intf.spi = 1;
|
||||
ssd1306_intf.start = ssd1306_spiStart_Usi;
|
||||
ssd1306_intf.stop = ssd1306_spiStop_Usi;
|
||||
ssd1306_intf.send = ssd1306_spiSendByte_Usi;
|
||||
ssd1306_intf.send_buffer = ssd1306_spiSendBytes_Usi;
|
||||
ssd1306_intf.close = ssd1306_spiClose_Usi;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_spi_usi.h SSD1306 SPI USI communication functions
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_SPI_USI_H_
|
||||
#define _SSD1306_SPI_USI_H_
|
||||
|
||||
#include "ssd1306_spi_conf.h"
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USI_SPI_AVAILABLE) && defined(CONFIG_USI_SPI_ENABLE)
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Inits lcd interface to use USI for SPI communication.
|
||||
* It uses standard USI CLK, USI DO, USI DI pins to send data to LCD.
|
||||
* @param cesPin - pin, controlling chip enable of LCD
|
||||
* @param dcPin - pin, controlling data/command mode of LCD
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_spiInit_Usi(int8_t cesPin, int8_t dcPin);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // _SSD1306_SPI_USI_H_
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_interface.h"
|
||||
#include "spi/ssd1306_spi.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static void ssd1306_send_buffer_generic(const uint8_t* buffer, uint16_t size);
|
||||
|
||||
ssd1306_interface_t ssd1306_intf =
|
||||
{
|
||||
.send_buffer = ssd1306_send_buffer_generic
|
||||
};
|
||||
|
||||
void ssd1306_commandStart(void)
|
||||
{
|
||||
ssd1306_intf.start();
|
||||
if (ssd1306_intf.spi)
|
||||
ssd1306_spiDataMode(0);
|
||||
else
|
||||
ssd1306_intf.send(0x00);
|
||||
}
|
||||
|
||||
void ssd1306_dataStart(void)
|
||||
{
|
||||
ssd1306_intf.start();
|
||||
if (ssd1306_intf.spi)
|
||||
ssd1306_spiDataMode(1);
|
||||
else
|
||||
ssd1306_intf.send(0x40);
|
||||
}
|
||||
|
||||
void ssd1306_sendCommand(uint8_t command)
|
||||
{
|
||||
ssd1306_commandStart();
|
||||
ssd1306_intf.send(command);
|
||||
ssd1306_intf.stop();
|
||||
}
|
||||
|
||||
void ssd1306_send_buffer_generic(const uint8_t* buffer, uint16_t size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
ssd1306_intf.send(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file ssd1306_interface.h SSD1306 interface functions.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SSD1306_INTERFACE_H_
|
||||
#define _SSD1306_INTERFACE_H_
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup LCD_HW_INTERFACE_API I2C/SPI: physical interface functions
|
||||
* @{
|
||||
*
|
||||
* @brief i2c/spi initialization functions for different platforms
|
||||
*
|
||||
* @details This group of API functions serves to prepare the library to work via specific hardware
|
||||
* interface. There are a bunch of functions for different platforms. In general display
|
||||
* initialization goes in two steps: hardware interface initialization, and then display
|
||||
* driver initialization. But there are functions, which combine 2 steps in single call:
|
||||
* ssd1306_128x64_i2c_initEx(), ssd1351_128x128_spi_init(), etc.
|
||||
*/
|
||||
|
||||
/** Describes low level hardware API */
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
* Indicates if spi or i2c interface is used.
|
||||
*/
|
||||
uint8_t spi;
|
||||
/**
|
||||
* Starts communication with SSD1306 display.
|
||||
*/
|
||||
void (*start)(void);
|
||||
/**
|
||||
* Ends communication with SSD1306 display.
|
||||
*/
|
||||
void (*stop)(void);
|
||||
/**
|
||||
* Sends byte to SSD1306 device
|
||||
* @param data - byte to send
|
||||
*/
|
||||
void (*send)(uint8_t data);
|
||||
/**
|
||||
* @brief Sends bytes to SSD1306 device
|
||||
*
|
||||
* Sends bytes to SSD1306 device. This functions gives
|
||||
* ~ 30% performance increase than ssd1306_intf.send.
|
||||
*
|
||||
* @param buffer - bytes to send
|
||||
* @param size - number of bytes to send
|
||||
*/
|
||||
void (*send_buffer)(const uint8_t *buffer, uint16_t size);
|
||||
/**
|
||||
* @brief deinitializes internal resources, allocated for interface.
|
||||
*
|
||||
* Deinitializes internal resources, allocated for interface.
|
||||
* There is no need to use this function for microcontrollers. In general
|
||||
* the function has meaning in Linux-like systems.
|
||||
*/
|
||||
void (*close)(void);
|
||||
} ssd1306_interface_t;
|
||||
|
||||
/**
|
||||
* Holds pointers to functions of currently initialized interface.
|
||||
*/
|
||||
extern ssd1306_interface_t ssd1306_intf;
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
*/
|
||||
#define ssd1306_dcQuickSwitch ssd1306_intf.spi
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
*/
|
||||
#define ssd1306_startTransmission ssd1306_intf.start
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
*/
|
||||
#define ssd1306_endTransmission ssd1306_intf.stop
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
*/
|
||||
#define ssd1306_sendByte ssd1306_intf.send
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
*/
|
||||
#define ssd1306_sendBytes ssd1306_intf.send_buffer
|
||||
|
||||
/**
|
||||
* Deprecated
|
||||
*/
|
||||
#define ssd1306_closeInterface ssd1306_intf.close
|
||||
|
||||
/**
|
||||
* Sends command to SSD1306 device: includes initiating of
|
||||
* transaction, sending data and completing transaction.
|
||||
* @param command - command to send
|
||||
*/
|
||||
void ssd1306_sendCommand(uint8_t command);
|
||||
|
||||
/**
|
||||
* Starts transaction for sending commands.
|
||||
*/
|
||||
void ssd1306_commandStart(void);
|
||||
|
||||
/**
|
||||
* Starts transaction for sending bitmap data.
|
||||
*/
|
||||
void ssd1306_dataStart(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // _SSD1306_INTERFACE_H_
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016-2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "ssd1306_uart_builtin.h"
|
||||
#include "intf/ssd1306_interface.h"
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_AVR_UART_AVAILABLE) && defined(CONFIG_AVR_UART_ENABLE)
|
||||
|
||||
#include "ssd1306_uart.h"
|
||||
|
||||
static void ssd1306_uartStart(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void ssd1306_uartStop(void)
|
||||
{
|
||||
uart_send_byte(0x7E);
|
||||
}
|
||||
|
||||
static void ssd1306_uartSendByte(uint8_t data)
|
||||
{
|
||||
if ((data == 0x7E) || (data == 0x7D))
|
||||
{
|
||||
uart_send_byte(0x7D);
|
||||
data ^= 0x20;
|
||||
}
|
||||
uart_send_byte(data);
|
||||
}
|
||||
|
||||
static void ssd1306_uartSendBytes(const uint8_t * buffer, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
ssd1306_uartSendByte(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
void ssd1306_uartInit_Builtin(uint32_t baud)
|
||||
{
|
||||
if (!baud) baud = 115200;
|
||||
uart_init(baud);
|
||||
ssd1306_intf.spi = 0;
|
||||
ssd1306_intf.start = ssd1306_uartStart;
|
||||
ssd1306_intf.stop = ssd1306_uartStop;
|
||||
ssd1306_intf.send = ssd1306_uartSendByte;
|
||||
ssd1306_intf.send_buffer = ssd1306_uartSendBytes;
|
||||
ssd1306_intf.close = ssd1306_uartStart;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file ssd1306_uart_builtin.h embedded SSD1306 uart communication functions
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_UART_BUILTIN_H_
|
||||
#define _SSD1306_UART_BUILTIN_H_
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_AVR_UART_AVAILABLE) && defined(CONFIG_AVR_UART_ENABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup LCD_HW_INTERFACE_API
|
||||
*
|
||||
* Initializes built-in implementation of uart functions, based on USART hw module.
|
||||
* If you do not know uart parameters, try ssd1306_uartInit_Builtin(0).
|
||||
* @param baud uart baud rate
|
||||
*
|
||||
* @note: after call to this function you need to initialize lcd display.
|
||||
*/
|
||||
void ssd1306_uartInit_Builtin(uint32_t baud);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SSD1306_UART_BUILTIN_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "intf/vga/vga.h"
|
||||
// Never include vga128x64_isr.h here!!!
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
#include "lcd/vga_commands.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
|
||||
|
||||
extern uint16_t ssd1306_color;
|
||||
|
||||
/* This buffer fits 128x64 pixels
|
||||
Each 8 pixels are packed to 3 bytes:
|
||||
|
||||
BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
|
||||
BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
|
||||
BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
|
||||
|
||||
Yeah, a little bit complicated, but this allows to quickly unpack structure
|
||||
*/
|
||||
|
||||
// Set to ssd1306 compatible mode by default
|
||||
static uint8_t s_mode = 0x01;
|
||||
static uint8_t s_vga_command = 0xFF;
|
||||
static uint8_t s_vga_arg = 0;
|
||||
static uint8_t s_column = 0;
|
||||
static uint8_t s_column_end = 0;
|
||||
static uint8_t s_cursor_x = 0;
|
||||
static uint8_t s_cursor_y = 0;
|
||||
volatile uint8_t s_vga_frames;
|
||||
|
||||
static void vga_controller_init(void)
|
||||
{
|
||||
s_vga_command = 0xFF;
|
||||
}
|
||||
|
||||
static void vga_controller_stop(void)
|
||||
{
|
||||
s_vga_command = 0xFF;
|
||||
}
|
||||
|
||||
static void vga_controller_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Function sends 8 vertical pixels to buffer
|
||||
*/
|
||||
static inline void vga_controller_put_pixels(uint8_t x, uint8_t y, uint8_t pixels)
|
||||
{
|
||||
uint16_t addr = (x >> 3) + (uint16_t)(y * 16);
|
||||
uint8_t offset = x & 0x07;
|
||||
uint8_t mask = 1 << offset;
|
||||
if (addr >= 16*64)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (uint8_t i=8; i>0; i--)
|
||||
{
|
||||
if (pixels & 0x01) __vga_buffer[addr] |= mask;
|
||||
else __vga_buffer[addr] &= ~mask;
|
||||
addr += 16;
|
||||
pixels >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void vga_controller_send_byte(uint8_t data)
|
||||
{
|
||||
if (s_vga_command == 0xFF)
|
||||
{
|
||||
s_vga_command = data;
|
||||
return;
|
||||
}
|
||||
if (s_vga_command == 0x40)
|
||||
{
|
||||
vga_controller_put_pixels(s_cursor_x, s_cursor_y, data);
|
||||
s_cursor_x++;
|
||||
if (s_cursor_x > s_column_end)
|
||||
{
|
||||
s_cursor_x = s_column;
|
||||
s_cursor_y += 8;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// command mode
|
||||
if (!s_vga_command)
|
||||
{
|
||||
s_vga_command = data;
|
||||
s_vga_arg = 0;
|
||||
}
|
||||
if (s_vga_command == VGA_SET_BLOCK)
|
||||
{
|
||||
// set block
|
||||
if (s_vga_arg == 1)
|
||||
{
|
||||
s_column = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data ;
|
||||
s_cursor_x = s_column;
|
||||
}
|
||||
if (s_vga_arg == 2) { s_column_end = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data; }
|
||||
if (s_vga_arg == 3) { s_cursor_y = (data << 3); }
|
||||
if (s_vga_arg == 4) { s_vga_command = 0; }
|
||||
}
|
||||
if (s_vga_command == VGA_SET_MODE)
|
||||
{
|
||||
if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
|
||||
}
|
||||
s_vga_arg++;
|
||||
}
|
||||
|
||||
static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
ssd1306_intf.send(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void init_vga_crt_driver(uint8_t enable_jitter_fix)
|
||||
{
|
||||
cli();
|
||||
if (enable_jitter_fix)
|
||||
{
|
||||
// Configure Timer 0 to calculate jitter fix
|
||||
TIMSK0=0;
|
||||
TCCR0A=0;
|
||||
TCCR0B=1;
|
||||
OCR0A=0;
|
||||
OCR0B=0;
|
||||
TCNT0=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sorry, we still need to disable timer0 interrupts to avoid wake up in sleep mode
|
||||
TIMSK0 &= ~(1<<TOIE0);
|
||||
}
|
||||
|
||||
// Timer 1 - vertical sync pulses
|
||||
pinMode (V_SYNC_PIN, OUTPUT);
|
||||
TCCR1A=(1<<WGM10) | (1<<WGM11) | (1<<COM1B1);
|
||||
TCCR1B=(1<<WGM12) | (1<<WGM13) | (1<<CS12) | (1<<CS10); //1024 prescaler
|
||||
OCR1A = 259; // 16666 / 64 us = 260 (less one)
|
||||
OCR1B = 0; // 64 / 64 us = 1 (less one)
|
||||
TIFR1 = (1<<TOV1); // clear overflow flag
|
||||
TIMSK1 = (1<<TOIE1); // interrupt on overflow on timer 1
|
||||
|
||||
// Timer 2 - horizontal sync pulses
|
||||
pinMode (H_SYNC_PIN, OUTPUT);
|
||||
TCCR2A=(1<<WGM20) | (1<<WGM21) | (1<<COM2B1); //pin3=COM2B1
|
||||
TCCR2B=(1<<WGM22) | (1<<CS21); //8 prescaler
|
||||
OCR2A = 63; // 32 / 0.5 us = 64 (less one)
|
||||
OCR2B = 7; // 4 / 0.5 us = 8 (less one)
|
||||
// if (enable_jitter_fix)
|
||||
{
|
||||
TIFR2 = (1<<OCF2B); // on end of h-sync pulse
|
||||
TIMSK2 = (1<<OCIE2B); // on end of h-sync pulse
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// TIFR2 = (1<<TOV2); // int on start of h-sync pulse
|
||||
// TIMSK2 = (1<<TOIE2); // int on start of h-sync pulse
|
||||
// }
|
||||
|
||||
// Set up USART in SPI mode (MSPIM)
|
||||
|
||||
pinMode(14, OUTPUT);
|
||||
pinMode(15, OUTPUT);
|
||||
pinMode(16, OUTPUT);
|
||||
PORTC = 0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
void ssd1306_vga_controller_128x64_init_no_output(void)
|
||||
{
|
||||
ssd1306_intf.spi = 0;
|
||||
ssd1306_intf.start = vga_controller_init;
|
||||
ssd1306_intf.stop = vga_controller_stop;
|
||||
ssd1306_intf.send = vga_controller_send_byte;
|
||||
ssd1306_intf.send_buffer = vga_controller_send_bytes;
|
||||
ssd1306_intf.close = vga_controller_close;
|
||||
}
|
||||
|
||||
void ssd1306_vga_controller_128x64_init_enable_output(void)
|
||||
{
|
||||
ssd1306_vga_controller_128x64_init_no_output();
|
||||
init_vga_crt_driver(1);
|
||||
}
|
||||
|
||||
void ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix(void)
|
||||
{
|
||||
ssd1306_vga_controller_128x64_init_no_output();
|
||||
init_vga_crt_driver(0);
|
||||
// set_sleep_mode (SLEEP_MODE_IDLE);
|
||||
}
|
||||
|
||||
void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t))
|
||||
{
|
||||
for(int y = 0; y < ssd1306_lcd.height; y++)
|
||||
{
|
||||
for(int x = 0; x < ssd1306_lcd.width; x++)
|
||||
{
|
||||
uint8_t color = __vga_buffer[(x >> 3) + y * 16] & (1<< (x&0x07));
|
||||
if (color)
|
||||
{
|
||||
func('#');
|
||||
func('#');
|
||||
}
|
||||
else
|
||||
{
|
||||
func(' ');
|
||||
func(' ');
|
||||
}
|
||||
}
|
||||
func('\n');
|
||||
}
|
||||
func('\n');
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "intf/vga/vga.h"
|
||||
// Never include vga96x40_isr.h here!!!
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
#include "lcd/vga_commands.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
|
||||
|
||||
extern uint16_t ssd1306_color;
|
||||
|
||||
/* This buffer fits 96x40 pixels
|
||||
Each 8 pixels are packed to 3 bytes:
|
||||
|
||||
BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
|
||||
BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
|
||||
BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
|
||||
|
||||
Yeah, a little bit complicated, but this allows to quickly unpack structure
|
||||
*/
|
||||
|
||||
// Set to ssd1306 compatible mode by default
|
||||
static uint8_t s_mode = 0x01;
|
||||
static uint8_t s_vga_command = 0xFF;
|
||||
static uint8_t s_vga_arg = 0;
|
||||
static uint8_t s_column = 0;
|
||||
static uint8_t s_column_end = 0;
|
||||
static uint8_t s_cursor_x = 0;
|
||||
static uint8_t s_cursor_y = 0;
|
||||
volatile uint8_t s_vga_frames;
|
||||
|
||||
static void vga_controller_init(void)
|
||||
{
|
||||
s_vga_command = 0xFF;
|
||||
}
|
||||
|
||||
static void vga_controller_stop(void)
|
||||
{
|
||||
s_vga_command = 0xFF;
|
||||
}
|
||||
|
||||
static void vga_controller_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* This buffer fits 96x40 pixels
|
||||
Each 8 pixels are packed to 3 bytes:
|
||||
|
||||
BYTE1: B7 R2 G2 B2 B8 R1 G1 B1
|
||||
BYTE2: G7 R4 G4 B4 G8 R3 G3 B3
|
||||
BYTE3: R7 R6 G6 B6 R8 R5 G5 B5
|
||||
|
||||
Yeah, a little bit complicated, but this allows to quickly unpack structure
|
||||
*/
|
||||
static inline void vga_controller_put_pixel3(uint8_t x, uint8_t y, uint8_t color)
|
||||
{
|
||||
uint16_t addr = (x >> 3)*3 + (uint16_t)y*36;
|
||||
uint8_t offset = x & 0x07;
|
||||
if (addr >= 36*40)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (offset < 6)
|
||||
{
|
||||
if (x&1)
|
||||
{
|
||||
__vga_buffer[addr + (offset>>1)] &= 0x8F;
|
||||
__vga_buffer[addr + (offset>>1)] |= (color<<4);
|
||||
}
|
||||
else
|
||||
{
|
||||
__vga_buffer[addr + (offset>>1)] &= 0xF8;
|
||||
__vga_buffer[addr + (offset>>1)] |= color;
|
||||
}
|
||||
}
|
||||
else if (offset == 6)
|
||||
{
|
||||
__vga_buffer[addr+0] &= 0x7F;
|
||||
__vga_buffer[addr+0] |= ((color & 0x01) << 7);
|
||||
__vga_buffer[addr+1] &= 0x7F;
|
||||
__vga_buffer[addr+1] |= ((color & 0x02) << 6);
|
||||
__vga_buffer[addr+2] &= 0x7F;
|
||||
__vga_buffer[addr+2] |= ((color & 0x04) << 5);
|
||||
}
|
||||
else // if (offset == 7)
|
||||
{
|
||||
__vga_buffer[addr+0] &= 0xF7;
|
||||
__vga_buffer[addr+0] |= ((color & 0x01) << 3);
|
||||
__vga_buffer[addr+1] &= 0xF7;
|
||||
__vga_buffer[addr+1] |= ((color & 0x02) << 2);
|
||||
__vga_buffer[addr+2] &= 0xF7;
|
||||
__vga_buffer[addr+2] |= ((color & 0x04) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void vga_controller_send_byte4(uint8_t data)
|
||||
{
|
||||
if (s_vga_command == 0xFF)
|
||||
{
|
||||
s_vga_command = data;
|
||||
return;
|
||||
}
|
||||
if (s_vga_command == 0x40)
|
||||
{
|
||||
uint8_t color = ((data & 0x80) >> 5) | ((data & 0x10) >> 3) | ((data & 0x02)>>1);
|
||||
vga_controller_put_pixel3(s_cursor_x, s_cursor_y, color);
|
||||
if (s_mode == 0x00)
|
||||
{
|
||||
s_cursor_x++;
|
||||
if (s_cursor_x > s_column_end)
|
||||
{
|
||||
s_cursor_x = s_column;
|
||||
s_cursor_y++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s_cursor_y++;
|
||||
if ((s_cursor_y & 0x07) == 0)
|
||||
{
|
||||
s_cursor_y -= 8;
|
||||
s_cursor_x++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// command mode
|
||||
if (!s_vga_command)
|
||||
{
|
||||
s_vga_command = data;
|
||||
s_vga_arg = 0;
|
||||
}
|
||||
if (s_vga_command == VGA_SET_BLOCK)
|
||||
{
|
||||
// set block
|
||||
if (s_vga_arg == 1) { s_column = data; s_cursor_x = data; }
|
||||
if (s_vga_arg == 2) { s_column_end = data; }
|
||||
if (s_vga_arg == 3) { s_cursor_y = data; }
|
||||
if (s_vga_arg == 4) { s_vga_command = 0; }
|
||||
}
|
||||
if (s_vga_command == VGA_SET_MODE)
|
||||
{
|
||||
if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
|
||||
}
|
||||
s_vga_arg++;
|
||||
}
|
||||
|
||||
static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
ssd1306_intf.send(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void init_vga_crt_driver(uint8_t enable_jitter_fix)
|
||||
{
|
||||
cli();
|
||||
if (enable_jitter_fix)
|
||||
{
|
||||
// Configure Timer 0 to calculate jitter fix
|
||||
TIMSK0=0;
|
||||
TCCR0A=0;
|
||||
TCCR0B=1;
|
||||
OCR0A=0;
|
||||
OCR0B=0;
|
||||
TCNT0=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sorry, we still need to disable timer0 interrupts to avoid wake up in sleep mode
|
||||
TIMSK0 &= ~(1<<TOIE0);
|
||||
}
|
||||
|
||||
// Timer 1 - vertical sync pulses
|
||||
pinMode (V_SYNC_PIN, OUTPUT);
|
||||
TCCR1A=(1<<WGM10) | (1<<WGM11) | (1<<COM1B1);
|
||||
TCCR1B=(1<<WGM12) | (1<<WGM13) | (1<<CS12) | (1<<CS10); //1024 prescaler
|
||||
OCR1A = 259; // 16666 / 64 us = 260 (less one)
|
||||
OCR1B = 0; // 64 / 64 us = 1 (less one)
|
||||
TIFR1 = (1<<TOV1); // clear overflow flag
|
||||
TIMSK1 = (1<<TOIE1); // interrupt on overflow on timer 1
|
||||
|
||||
// Timer 2 - horizontal sync pulses
|
||||
pinMode (H_SYNC_PIN, OUTPUT);
|
||||
TCCR2A=(1<<WGM20) | (1<<WGM21) | (1<<COM2B1); //pin3=COM2B1
|
||||
TCCR2B=(1<<WGM22) | (1<<CS21); //8 prescaler
|
||||
OCR2A = 63; // 32 / 0.5 us = 64 (less one)
|
||||
OCR2B = 7; // 4 / 0.5 us = 8 (less one)
|
||||
// if (enable_jitter_fix)
|
||||
{
|
||||
TIFR2 = (1<<OCF2B); // on end of h-sync pulse
|
||||
TIMSK2 = (1<<OCIE2B); // on end of h-sync pulse
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// TIFR2 = (1<<TOV2); // int on start of h-sync pulse
|
||||
// TIMSK2 = (1<<TOIE2); // int on start of h-sync pulse
|
||||
// }
|
||||
|
||||
// Set up USART in SPI mode (MSPIM)
|
||||
|
||||
pinMode(14, OUTPUT);
|
||||
pinMode(15, OUTPUT);
|
||||
pinMode(16, OUTPUT);
|
||||
PORTC = 0;
|
||||
|
||||
sei();
|
||||
}
|
||||
|
||||
void ssd1306_vga_controller_96x40_init_no_output(void)
|
||||
{
|
||||
ssd1306_intf.spi = 0;
|
||||
ssd1306_intf.start = vga_controller_init;
|
||||
ssd1306_intf.stop = vga_controller_stop;
|
||||
ssd1306_intf.send = vga_controller_send_byte4;
|
||||
ssd1306_intf.send_buffer = vga_controller_send_bytes;
|
||||
ssd1306_intf.close = vga_controller_close;
|
||||
}
|
||||
|
||||
void ssd1306_vga_controller_96x40_init_enable_output(void)
|
||||
{
|
||||
ssd1306_vga_controller_96x40_init_no_output();
|
||||
init_vga_crt_driver(1);
|
||||
}
|
||||
|
||||
void ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix(void)
|
||||
{
|
||||
ssd1306_vga_controller_96x40_init_no_output();
|
||||
init_vga_crt_driver(0);
|
||||
// set_sleep_mode (SLEEP_MODE_IDLE);
|
||||
}
|
||||
|
||||
void ssd1306_debug_print_vga_buffer_96x40(void (*func)(uint8_t))
|
||||
{
|
||||
for(int y = 0; y < ssd1306_lcd.height; y++)
|
||||
{
|
||||
for(int x = 0; x < ssd1306_lcd.width; x++)
|
||||
{
|
||||
uint8_t color = (__vga_buffer[(y*ssd1306_lcd.width + x)/2] >> ((x&1)<<2)) & 0x0F;
|
||||
if (color)
|
||||
{
|
||||
func('#');
|
||||
func('#');
|
||||
}
|
||||
else
|
||||
{
|
||||
func(' ');
|
||||
func(' ');
|
||||
}
|
||||
}
|
||||
func('\n');
|
||||
}
|
||||
func('\n');
|
||||
}
|
||||
|
||||
void ssd1306_vga_delay(uint32_t ms)
|
||||
{
|
||||
while (ms >= 16)
|
||||
{
|
||||
uint8_t vga_frames;
|
||||
vga_frames = s_vga_frames;
|
||||
while (vga_frames == s_vga_frames);
|
||||
ms-=16;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file vga_isr.h VGA ISR code to communicate with VGA-monitor from the sketch directly
|
||||
*
|
||||
* @details Please, include this file only once in your sketch, if you want to control
|
||||
* vga monitor directly from your sketch.
|
||||
* This header supports different modes: VGA_CONTROLLER_DEBUG, SSD1306_VGA_SLEEP_MODE.
|
||||
* If you want to use vga_controller module in debug mode without producing VGA output,
|
||||
* define VGA_CONTROLLER_DEBUG before including this header. If you want to use library with
|
||||
* AVR sleep mode, then jitter fix is not required, you will able to use TIMER0, so define
|
||||
* SSD1306_VGA_SLEEP_MODE before including this header.
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_VGA_ATMEGA328P_ISR_H_
|
||||
#define _SSD1306_VGA_ATMEGA328P_ISR_H_
|
||||
|
||||
#include "intf/vga/vga.h"
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Including this header defines ISR handlers in your application automatically
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__AVR_ATmega328P__)
|
||||
|
||||
#ifndef DEJITTER_OFFSET
|
||||
#define DEJITTER_OFFSET -4
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_VGA_128X64_ENABLE)
|
||||
|
||||
static const uint16_t __VGA_VERTICAL_PIXELS = 64;
|
||||
static const uint16_t __VGA_LINE_BYTES = 16;
|
||||
static const uint16_t __VGA_PIXEL_HEIGHT = 7;
|
||||
volatile uint8_t __vga_buffer[16*64] = {0};
|
||||
static const volatile uint8_t *__VGA_BUFFER_PTR = &__vga_buffer[0];
|
||||
|
||||
void ssd1306_vga_controller_128x64_init_no_output(void);
|
||||
void ssd1306_vga_controller_128x64_init_enable_output(void);
|
||||
void ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix(void);
|
||||
void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t));
|
||||
|
||||
#elif defined(CONFIG_VGA_96X40_ENABLE)
|
||||
|
||||
static const uint16_t __VGA_VERTICAL_PIXELS = 40;
|
||||
static const uint16_t __VGA_LINE_BYTES = 36;
|
||||
static const uint16_t __VGA_PIXEL_HEIGHT = 10;
|
||||
volatile uint8_t __vga_buffer[36*40] = {0};
|
||||
static const volatile uint8_t * __VGA_BUFFER_PTR = &__vga_buffer[0];
|
||||
|
||||
void ssd1306_vga_controller_96x40_init_no_output(void);
|
||||
void ssd1306_vga_controller_96x40_init_enable_output(void);
|
||||
void ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix(void);
|
||||
void ssd1306_debug_print_vga_buffer_96x40(void (*func)(uint8_t));
|
||||
|
||||
#else
|
||||
#error "Please, define one of VGA options"
|
||||
#endif
|
||||
|
||||
#if !defined(VGA_CONTROLLER_DEBUG)
|
||||
|
||||
// Total number of lines used in specific scan mode
|
||||
static const uint16_t VGA_TOTAL_MODE_LINES = __VGA_VERTICAL_PIXELS*__VGA_PIXEL_HEIGHT;
|
||||
|
||||
// Lines to skip before starting to draw first line of the screen content
|
||||
// This includes V-sync signal + front porch
|
||||
static const uint8_t V_BACKPORCH_LINES = 40;
|
||||
|
||||
// Lines to skip before starting to draw first line of the screen content
|
||||
// This includes V-sync signal + front porch
|
||||
volatile int s_current_scan_line;
|
||||
|
||||
volatile uint8_t s_lines_to_skip;
|
||||
volatile uint8_t s_scan_line_index;
|
||||
volatile const uint8_t * volatile s_current_scan_line_data = __VGA_BUFFER_PTR;
|
||||
extern volatile uint8_t s_vga_frames;
|
||||
extern unsigned long timer0_millis;
|
||||
// ISR: Vsync pulse
|
||||
ISR(TIMER1_OVF_vect)
|
||||
{
|
||||
s_current_scan_line = 0;
|
||||
s_scan_line_index = 0;
|
||||
s_current_scan_line_data = __VGA_BUFFER_PTR;
|
||||
s_lines_to_skip = V_BACKPORCH_LINES;
|
||||
s_vga_frames++;
|
||||
timer0_millis += 16;
|
||||
} // end of TIMER1_OVF_vect
|
||||
|
||||
#if defined(CONFIG_VGA_128X64_ENABLE)
|
||||
static inline void /*__attribute__ ((noinline))*/ do_scan_line()
|
||||
{
|
||||
// output all pixels
|
||||
|
||||
asm volatile(
|
||||
".rept 16\n\t"
|
||||
|
||||
"ld r24, Z+\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
"lsr r24\n\t"
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t"
|
||||
|
||||
".endr\n\t"
|
||||
"nop\n\t"
|
||||
"ldi r24,0\n\t"
|
||||
"out %[port], r24 \n\t"
|
||||
"nop\n\t"
|
||||
:
|
||||
: [port] "I" (_SFR_IO_ADDR(PORTC)),
|
||||
"z" "I" ((uint8_t *)s_current_scan_line_data )
|
||||
: "r24", "memory"
|
||||
);
|
||||
}
|
||||
#elif defined(CONFIG_VGA_96X40_ENABLE)
|
||||
static inline void /*__attribute__ ((noinline))*/ do_scan_line()
|
||||
{
|
||||
// output all pixels
|
||||
|
||||
asm volatile(
|
||||
".rept 12\n\t"
|
||||
|
||||
"ld r24, Z+\n\t" // r24 = 82227111
|
||||
// "nop\n\t" // to make pixel wider in 96x40 mode
|
||||
"out %[port], r24\n\t" // 111
|
||||
|
||||
"ld r25, Z+\n\t" // r25 = 84447333
|
||||
"swap r24\n\t" // r24 = 71118222
|
||||
"out %[port], r24\n\t" // 222
|
||||
|
||||
"andi r24, 0x88\n\t" // r24 = 70008000
|
||||
"ld r20, Z+\n\t" // r20 = 86667555
|
||||
"out %[port], r25\n\t" // 333
|
||||
|
||||
"swap r25\n\t" // r25 = 73338444
|
||||
"lsr r24\n\t" // r24 = 00080007
|
||||
"lsr r24\n\t" // r24 = 00800070
|
||||
"out %[port], r25\n\t" // 444
|
||||
|
||||
"andi r25, 0x88\n\t" // r25 = 70008000
|
||||
"lsr r24\n\t" // r24 = 08000700
|
||||
"lsr r25\n\t" // r25 = 00080007
|
||||
"out %[port], r20\n\t" // 555
|
||||
|
||||
"swap r20\n\t" // r20 = 75558666
|
||||
"lsr r25\n\t" // r25 = 00800070
|
||||
"or r24, r25\n\t" // r24 = 08800770
|
||||
"out %[port], r20\n\t" // 666
|
||||
|
||||
"andi r20, 0x88\n\t" // r20 = 70008000
|
||||
"lsr r20\n\t" // r20 = 00080007 b
|
||||
"or r24, r20\n\t" // r24 = 08880777 rgb
|
||||
"out %[port], r24\n\t" // 777
|
||||
|
||||
"swap r24\n\t" // r24 = 07770888
|
||||
// "nop\n\t" // to make pixel wider in 96x40 mode
|
||||
"nop\n\t"
|
||||
"out %[port], r24\n\t" // 888
|
||||
|
||||
".endr\n\t"
|
||||
// "nop\n\t" // to make pixel wider in 96x40 mode
|
||||
"nop\n\t"
|
||||
"ldi r24,0\n\t"
|
||||
"out %[port], r24 \n\t"
|
||||
"nop\n\t"
|
||||
:
|
||||
: [port] "I" (_SFR_IO_ADDR(PORTC)),
|
||||
"z" "I" ((uint8_t *)s_current_scan_line_data )
|
||||
: "r24", "r25", "r20", "memory"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
//#ifdef SSD1306_VGA_SLEEP_MODE
|
||||
//ISR(TIMER2_OVF_vect) // for start of h-sync pulse
|
||||
//#else
|
||||
ISR(TIMER2_COMPB_vect) // for end of h-sync pulse
|
||||
//#endif
|
||||
{
|
||||
// ISR should work as fast as possible
|
||||
if (s_lines_to_skip)
|
||||
{
|
||||
s_lines_to_skip--;
|
||||
return;
|
||||
}
|
||||
else if (s_current_scan_line >= VGA_TOTAL_MODE_LINES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#ifndef SSD1306_VGA_SLEEP_MODE
|
||||
// This is dejitter code, it purpose to start pixels output at the same offset after h-sync
|
||||
asm volatile(
|
||||
" lds r24, %[timer0] \n\t" //
|
||||
" subi r24, %[toffset] \n\t" // some offset, calculated experimentally
|
||||
" andi r24, 7 \n\t" // use module 8 value from Timer 0 counter
|
||||
" ldi r31, pm_hi8(LW) \n\t" // load label address
|
||||
" ldi r30, pm_lo8(LW) \n\t" //
|
||||
" add r30, r24 \n\t" // no need to multiply by 2 since AVR addresses are half-values
|
||||
" adc r31, __zero_reg__ \n\t" //
|
||||
" ijmp \n\t" //
|
||||
"LW: \n\t" //
|
||||
" nop \n\t" //
|
||||
" nop \n\t" //
|
||||
" nop \n\t" //
|
||||
" nop \n\t" //
|
||||
" nop \n\t" //
|
||||
" nop \n\t" //
|
||||
" nop \n\t" //
|
||||
:
|
||||
: [timer0] "i" (&TCNT0),
|
||||
[toffset] "i" ((uint8_t)DEJITTER_OFFSET)
|
||||
: "r30", "r31", "r24", "r25");
|
||||
#endif
|
||||
do_scan_line();
|
||||
s_current_scan_line++;
|
||||
s_scan_line_index++;
|
||||
if ( s_scan_line_index >= __VGA_PIXEL_HEIGHT )
|
||||
{
|
||||
s_scan_line_index=0;
|
||||
s_current_scan_line_data += __VGA_LINE_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VGA_CONTROLLER_DEBUG
|
||||
|
||||
#if defined(CONFIG_VGA_128X64_ENABLE)
|
||||
|
||||
static inline void ssd1306_vga_controller_init(void)
|
||||
{
|
||||
// if there is no builtin support then only debug mode is available
|
||||
#if defined(VGA_CONTROLLER_DEBUG)
|
||||
ssd1306_vga_controller_128x64_init_no_output();
|
||||
#elif defined(SSD1306_VGA_SLEEP_MODE)
|
||||
ssd1306_vga_controller_128x64_init_enable_output_no_jitter_fix();
|
||||
#else
|
||||
ssd1306_vga_controller_128x64_init_enable_output();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
|
||||
{
|
||||
ssd1306_debug_print_vga_buffer_128x64(func);
|
||||
}
|
||||
|
||||
#elif defined(CONFIG_VGA_96X40_ENABLE)
|
||||
|
||||
static inline void ssd1306_vga_controller_init(void)
|
||||
{
|
||||
// if there is no builtin support then only debug mode is available
|
||||
#if defined(VGA_CONTROLLER_DEBUG)
|
||||
ssd1306_vga_controller_96x40_init_no_output();
|
||||
#elif defined(SSD1306_VGA_SLEEP_MODE)
|
||||
ssd1306_vga_controller_96x40_init_enable_output_no_jitter_fix();
|
||||
#else
|
||||
ssd1306_vga_controller_96x40_init_enable_output();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
|
||||
{
|
||||
ssd1306_debug_print_vga_buffer_96x40(func);
|
||||
}
|
||||
|
||||
#endif // CONFIG_VGA_XXX_ENABLE
|
||||
|
||||
#endif // SSD1306_BUILTIN_VGA_SUPPORT
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Credits to https://github.com/bitluni/ESP32CompositeVideo
|
||||
*/
|
||||
|
||||
#include "CompositeOutput.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__XTENSA__)
|
||||
|
||||
#include "driver/i2s.h"
|
||||
|
||||
#define I2S_VGA_SAMPLE_RATE (4000000)
|
||||
static const i2s_port_t I2S_PORT = (i2s_port_t)I2S_NUM_0;
|
||||
|
||||
const TechProperties PALProperties = {
|
||||
.lineMicros = 64,
|
||||
.syncMicros = 4.7,
|
||||
.blankEndMicros = 10.4,
|
||||
.backMicros = 1.65,
|
||||
.shortVSyncMicros = 2.35,
|
||||
.overscanLeftMicros = 1.6875,
|
||||
.overscanRightMicros = 1.6875,
|
||||
.syncVolts = -0.3,
|
||||
.blankVolts = 0.0,
|
||||
.blackVolts = 0.005,//specs 0.0,
|
||||
.whiteVolts = 0.7,
|
||||
.lines = 625,
|
||||
.linesFirstTop = 23,
|
||||
.linesOverscanTop = 9,
|
||||
.linesOverscanBottom = 9,
|
||||
.imageAspect = 4./3.
|
||||
};
|
||||
|
||||
const TechProperties NTSCProperties = {
|
||||
.lineMicros = 63.492,
|
||||
.syncMicros = 4.7,
|
||||
.blankEndMicros = 9.2,
|
||||
.backMicros = 1.5,
|
||||
.shortVSyncMicros = 2.3,
|
||||
.overscanLeftMicros = 0,//1.3,
|
||||
.overscanRightMicros = 0,//1,
|
||||
.syncVolts = -0.286,
|
||||
.blankVolts = 0.0,
|
||||
.blackVolts = 0.05, //specs 0.054,
|
||||
.whiteVolts = 0.714,
|
||||
.lines = 525,
|
||||
.linesFirstTop = 20,
|
||||
.linesOverscanTop = 6,
|
||||
.linesOverscanBottom = 9,
|
||||
.imageAspect = 4./3.
|
||||
};
|
||||
|
||||
CompositeOutput::CompositeOutput(Mode mode, double Vcc)
|
||||
:properties((mode==NTSC) ? NTSCProperties: PALProperties)
|
||||
{
|
||||
double dacPerVolt = 255.0 / Vcc;
|
||||
levelSync = 0;
|
||||
levelBlank = (properties.blankVolts - properties.syncVolts) * dacPerVolt + 0.5;
|
||||
levelBlack = (properties.blackVolts - properties.syncVolts) * dacPerVolt + 0.5;
|
||||
levelWhite = (properties.whiteVolts - properties.syncVolts) * dacPerVolt + 0.5;
|
||||
grayValues = levelWhite - levelBlack + 1;
|
||||
}
|
||||
|
||||
void CompositeOutput::init(int xres, int yres, int bpp)
|
||||
{
|
||||
const int LINES_SYNC_TOP = 5;
|
||||
const int LINES_SYNC_BOTTOM = 3;
|
||||
|
||||
m_buffer_width = xres;
|
||||
m_buffer_height = yres;
|
||||
m_bpp = bpp;
|
||||
|
||||
linesOdd = properties.lines / 2;
|
||||
linesEven = properties.lines - linesOdd;
|
||||
linesEvenActive = linesEven - properties.linesFirstTop - LINES_SYNC_BOTTOM;
|
||||
linesOddActive = linesOdd - properties.linesFirstTop - LINES_SYNC_BOTTOM;
|
||||
linesEvenVisible = linesEvenActive - properties.linesOverscanTop - properties.linesOverscanBottom;
|
||||
linesOddVisible = linesOddActive - properties.linesOverscanTop - properties.linesOverscanBottom;
|
||||
|
||||
targetYresOdd = (yres / 2 < linesOddVisible) ? yres / 2 : linesOddVisible;
|
||||
targetYresEven = (yres - targetYresOdd < linesEvenVisible) ? yres - targetYresOdd : linesEvenVisible;
|
||||
targetYres = targetYresEven + targetYresOdd;
|
||||
|
||||
linesEvenBlankTop = properties.linesFirstTop - LINES_SYNC_TOP + properties.linesOverscanTop + (linesEvenVisible - targetYresEven) / 2;
|
||||
linesEvenBlankBottom = linesEven - linesEvenBlankTop - targetYresEven - LINES_SYNC_BOTTOM;
|
||||
linesOddBlankTop = linesEvenBlankTop;
|
||||
linesOddBlankBottom = linesOdd - linesOddBlankTop - targetYresOdd - LINES_SYNC_BOTTOM;
|
||||
|
||||
double samplesPerSecond = I2S_VGA_SAMPLE_RATE;
|
||||
double samplesPerMicro = samplesPerSecond * 0.000001;
|
||||
m_samples_per_line = (int)(samplesPerMicro * properties.lineMicros + 1.5) & ~1;
|
||||
samplesSync = samplesPerMicro * properties.syncMicros + 0.5;
|
||||
samplesBlank = samplesPerMicro * (properties.blankEndMicros - properties.syncMicros + properties.overscanLeftMicros) + 0.5;
|
||||
samplesBack = samplesPerMicro * (properties.backMicros + properties.overscanRightMicros) + 0.5;
|
||||
samplesActive = m_samples_per_line - samplesSync - samplesBlank - samplesBack;
|
||||
|
||||
targetXres = xres < samplesActive ? xres : samplesActive;
|
||||
|
||||
samplesVSyncShort = samplesPerMicro * properties.shortVSyncMicros + 0.5;
|
||||
|
||||
samplesBlackLeft = (samplesActive - targetXres) / 2;
|
||||
samplesBlackRight = samplesActive - targetXres - samplesBlackLeft;
|
||||
|
||||
// pixelAspect = (float(samplesActive) / (linesEvenVisible + linesOddVisible)) / properties.imageAspect;
|
||||
|
||||
line = (uint16_t*)malloc(sizeof(uint16_t) * m_samples_per_line * 2);
|
||||
m_ptr = line;
|
||||
m_end = line + m_samples_per_line * 2;
|
||||
|
||||
init_hardware();
|
||||
}
|
||||
|
||||
void CompositeOutput::init_hardware()
|
||||
{
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
|
||||
.sample_rate = I2S_VGA_SAMPLE_RATE, //not really used
|
||||
.bits_per_sample = (i2s_bits_per_sample_t)I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
|
||||
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
.dma_buf_count = 2,
|
||||
.dma_buf_len = m_samples_per_line //a buffer per line
|
||||
};
|
||||
|
||||
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); //start i2s driver
|
||||
i2s_set_pin(I2S_PORT, NULL); //use internal DAC
|
||||
i2s_set_sample_rates(I2S_PORT, I2S_VGA_SAMPLE_RATE); //dummy sample rate, since the function fails at high values
|
||||
}
|
||||
|
||||
void CompositeOutput::fillValues(uint8_t value, int count)
|
||||
{
|
||||
for(int j = 0; j < count; j++)
|
||||
{
|
||||
*m_ptr = ((uint16_t)value << 8);
|
||||
m_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
void CompositeOutput::sendFrameHalfResolution(const uint8_t *frame)
|
||||
{
|
||||
generate_long_sync(); // 1
|
||||
generate_long_sync(); // 2
|
||||
generate_long_short_sync(); // 3
|
||||
generate_short_sync(); // 4
|
||||
generate_short_sync(); // 5
|
||||
for (int y = 0; y < linesEvenBlankTop; y++)
|
||||
{
|
||||
generate_blank_line(); // top blank lines
|
||||
}
|
||||
|
||||
for (int y = 0; y < targetYresEven; y++)
|
||||
{
|
||||
generate_line_from_buffer( &frame[(y >> 3)*(m_buffer_width * m_bpp / 8)] ); // real data
|
||||
}
|
||||
for (int y = 0; y < linesEvenBlankBottom; y++)
|
||||
{
|
||||
generate_blank_line(); // bottom blank lines
|
||||
}
|
||||
generate_short_sync(); // 311
|
||||
generate_short_sync(); // 312
|
||||
|
||||
generate_short_long_sync(); // 313
|
||||
generate_long_sync(); // 314
|
||||
generate_long_sync(); // 315
|
||||
generate_short_sync(); // 316
|
||||
generate_short_sync(); // 317
|
||||
|
||||
generate_short_blank_sync(); // 318
|
||||
for (int y = 0; y < linesOddBlankTop; y++)
|
||||
{
|
||||
generate_blank_line(); // top blank lines
|
||||
}
|
||||
for (int y = 0; y < targetYresOdd; y++)
|
||||
{
|
||||
generate_line_from_buffer( &frame[(y>>3)*(m_buffer_width * m_bpp / 8)] ); // real data
|
||||
}
|
||||
for(int y = 0; y < linesOddBlankBottom; y++)
|
||||
{
|
||||
generate_blank_line(); // bottom blank lines
|
||||
}
|
||||
generate_blank_short_sync(); // 623
|
||||
generate_short_sync(); // 624
|
||||
generate_short_sync(); // 625
|
||||
if (m_ptr != line) // force to send data
|
||||
{
|
||||
size_t bytes_written;
|
||||
i2s_write(I2S_PORT, (char*)line, (m_ptr - line) * sizeof(uint16_t), &bytes_written, portMAX_DELAY);
|
||||
m_ptr = line;
|
||||
}
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_long_sync()
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
fillValues(levelSync, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
fillValues(levelBlank, samplesVSyncShort);
|
||||
}
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_short_sync()
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
fillValues(levelSync, samplesVSyncShort);
|
||||
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
}
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_long_short_sync()
|
||||
{
|
||||
fillValues(levelSync, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
fillValues(levelBlank, samplesVSyncShort);
|
||||
fillValues(levelSync, samplesVSyncShort);
|
||||
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_short_long_sync()
|
||||
{
|
||||
fillValues(levelSync, samplesVSyncShort);
|
||||
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
fillValues(levelSync, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
fillValues(levelBlank, samplesVSyncShort);
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_short_blank_sync()
|
||||
{
|
||||
fillValues(levelSync, samplesVSyncShort);
|
||||
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
fillValues(levelBlank, m_samples_per_line / 2);
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_blank_short_sync()
|
||||
{
|
||||
fillValues(levelSync, samplesSync);
|
||||
fillValues(levelBlank, m_samples_per_line / 2 - samplesSync);
|
||||
fillValues(levelSync, samplesVSyncShort);
|
||||
fillValues(levelBlank, m_samples_per_line / 2 - samplesVSyncShort);
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
void CompositeOutput::generate_blank_line()
|
||||
{
|
||||
fillValues(levelSync, samplesSync);
|
||||
fillValues(levelBlank, samplesBlank);
|
||||
fillValues(levelBlack, samplesActive);
|
||||
fillValues(levelBlank, samplesBack);
|
||||
check_buffer();
|
||||
}
|
||||
|
||||
const uint8_t* CompositeOutput::generate_line_from_buffer(const uint8_t *pixels)
|
||||
{
|
||||
fillValues(levelSync, samplesSync);
|
||||
fillValues(levelBlank, samplesBlank);
|
||||
fillValues(levelBlack, samplesBlackLeft);
|
||||
for (int x = 0; x < targetXres; x++)
|
||||
{
|
||||
uint8_t color = pixels[(x >> 3)] & (1<< (x&0x07));
|
||||
// *m_ptr = (levelBlack + pixels[x]) << 8;
|
||||
*m_ptr = (levelBlack + (color ? 0x80: 0x00 )) << 8;
|
||||
m_ptr++;
|
||||
}
|
||||
fillValues(levelBlack, samplesBlackRight);
|
||||
fillValues(levelBlank, samplesBack);
|
||||
check_buffer();
|
||||
return pixels + m_buffer_width * m_bpp / 8;
|
||||
// return pixels + targetXres;
|
||||
}
|
||||
|
||||
void CompositeOutput::check_buffer()
|
||||
{
|
||||
if (m_ptr == m_end)
|
||||
{
|
||||
size_t bytes_written;
|
||||
i2s_write(I2S_PORT, (char*)line, sizeof(uint16_t) * (m_end - line), &bytes_written, portMAX_DELAY);
|
||||
m_ptr = line;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Credits to https://github.com/bitluni/ESP32CompositeVideo
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(__XTENSA__)
|
||||
|
||||
#include <stdint.h>
|
||||
#include "driver/i2s.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float lineMicros;
|
||||
float syncMicros;
|
||||
float blankEndMicros;
|
||||
float backMicros;
|
||||
float shortVSyncMicros;
|
||||
float overscanLeftMicros;
|
||||
float overscanRightMicros;
|
||||
float syncVolts;
|
||||
float blankVolts;
|
||||
float blackVolts;
|
||||
float whiteVolts;
|
||||
short lines;
|
||||
short linesFirstTop;
|
||||
short linesOverscanTop;
|
||||
short linesOverscanBottom;
|
||||
float imageAspect;
|
||||
} TechProperties;
|
||||
|
||||
class CompositeOutput
|
||||
{
|
||||
public:
|
||||
|
||||
enum Mode
|
||||
{
|
||||
PAL,
|
||||
NTSC
|
||||
};
|
||||
|
||||
CompositeOutput(Mode mode, double Vcc = 3.3);
|
||||
|
||||
void init(int xres, int yres, int bpp);
|
||||
|
||||
void fillValues(uint8_t value, int count);
|
||||
|
||||
void sendFrameHalfResolution(const uint8_t *frame);
|
||||
|
||||
private:
|
||||
const TechProperties &properties;
|
||||
|
||||
int m_samples_per_line = 0;
|
||||
int samplesSync = 0;
|
||||
int samplesBlank = 0;
|
||||
int samplesBack = 0;
|
||||
int samplesActive = 0;
|
||||
int samplesBlackLeft = 0;
|
||||
int samplesBlackRight = 0;
|
||||
|
||||
int samplesVSyncShort = 0;
|
||||
int samplesVSyncLong = 0;
|
||||
|
||||
uint8_t levelSync = 0;
|
||||
uint8_t levelBlank = 0;
|
||||
uint8_t levelBlack = 0;
|
||||
uint8_t levelWhite = 0;
|
||||
uint8_t grayValues = 0;
|
||||
|
||||
int targetXres = 0;
|
||||
int targetYres = 0;
|
||||
int targetYresEven = 0;
|
||||
int targetYresOdd = 0;
|
||||
|
||||
int linesEven = 0;
|
||||
int linesOdd = 0;
|
||||
int linesEvenActive = 0;
|
||||
int linesOddActive = 0;
|
||||
int linesEvenVisible = 0;
|
||||
int linesOddVisible = 0;
|
||||
int linesEvenBlankTop = 0;
|
||||
int linesEvenBlankBottom = 0;
|
||||
int linesOddBlankTop = 0;
|
||||
int linesOddBlankBottom = 0;
|
||||
|
||||
int m_buffer_width = 0;
|
||||
int m_buffer_height = 0;
|
||||
int m_bpp = 0;
|
||||
|
||||
// float pixelAspect;
|
||||
|
||||
uint16_t *line = nullptr;
|
||||
uint16_t *m_end = nullptr;
|
||||
uint16_t *m_ptr = nullptr;
|
||||
|
||||
void init_hardware();
|
||||
void check_buffer();
|
||||
void generate_vsync();
|
||||
void generate_long_sync();
|
||||
void generate_short_sync();
|
||||
void generate_long_short_sync();
|
||||
void generate_short_long_sync();
|
||||
void generate_short_blank_sync();
|
||||
void generate_blank_short_sync();
|
||||
void generate_blank_line();
|
||||
const uint8_t * generate_line_from_buffer(const uint8_t * buffer);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "intf/ssd1306_interface.h"
|
||||
#include "intf/vga/vga.h"
|
||||
#include "lcd/lcd_common.h"
|
||||
#include "lcd/vga_commands.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(ESP32)
|
||||
|
||||
#include "CompositeOutput.h"
|
||||
|
||||
//#define VGA_CONTROLLER_DEBUG
|
||||
|
||||
static uint8_t *__vga_buffer = nullptr;
|
||||
extern uint16_t ssd1306_color;
|
||||
|
||||
// Set to ssd1306 compatible mode by default
|
||||
static uint8_t s_mode = 0x01;
|
||||
static uint8_t s_vga_command = 0xFF;
|
||||
static uint8_t s_vga_arg = 0;
|
||||
static uint8_t s_column = 0;
|
||||
static uint8_t s_column_end = 0;
|
||||
static uint8_t s_cursor_x = 0;
|
||||
static uint8_t s_cursor_y = 0;
|
||||
static uint8_t s_width = 0;
|
||||
static uint8_t s_height = 0;
|
||||
static uint8_t s_bpp = 0;
|
||||
|
||||
static CompositeOutput output(CompositeOutput::PAL);
|
||||
|
||||
static void compositeCore(void *data)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
//just send the graphics frontbuffer whithout any interruption
|
||||
output.sendFrameHalfResolution(__vga_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void vga_controller_init(void)
|
||||
{
|
||||
s_vga_command = 0xFF;
|
||||
}
|
||||
|
||||
#ifdef VGA_CONTROLLER_DEBUG
|
||||
#include <stdio.h>
|
||||
void uart_send_byte(uint8_t data)
|
||||
{
|
||||
printf("%c", data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void vga_controller_stop(void)
|
||||
{
|
||||
s_vga_command = 0xFF;
|
||||
#ifdef VGA_CONTROLLER_DEBUG
|
||||
ssd1306_debug_print_vga_buffer( uart_send_byte );
|
||||
#endif
|
||||
}
|
||||
|
||||
static void vga_controller_close(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Function sends 8 vertical pixels to buffer
|
||||
*/
|
||||
static inline void vga_controller_put_pixels(uint8_t x, uint8_t y, uint8_t pixels)
|
||||
{
|
||||
uint16_t addr = (x >> 3) + (uint16_t)(y * 16);
|
||||
uint8_t offset = x & 0x07;
|
||||
uint8_t mask = 1 << offset;
|
||||
if (addr >= 16*64)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (uint8_t i=8; i>0; i--)
|
||||
{
|
||||
if (pixels & 0x01) __vga_buffer[addr] |= mask;
|
||||
else __vga_buffer[addr] &= ~mask;
|
||||
addr += 16;
|
||||
pixels >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void vga_controller_send_byte(uint8_t data)
|
||||
{
|
||||
if (s_vga_command == 0xFF)
|
||||
{
|
||||
s_vga_command = data;
|
||||
return;
|
||||
}
|
||||
if (s_vga_command == 0x40)
|
||||
{
|
||||
vga_controller_put_pixels(s_cursor_x, s_cursor_y, data);
|
||||
s_cursor_x++;
|
||||
if (s_cursor_x > s_column_end)
|
||||
{
|
||||
s_cursor_x = s_column;
|
||||
s_cursor_y += 8;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// command mode
|
||||
if (!s_vga_command)
|
||||
{
|
||||
s_vga_command = data;
|
||||
s_vga_arg = 0;
|
||||
}
|
||||
if (s_vga_command == VGA_SET_BLOCK)
|
||||
{
|
||||
// set block
|
||||
if (s_vga_arg == 1)
|
||||
{
|
||||
s_column = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data ;
|
||||
s_cursor_x = s_column;
|
||||
}
|
||||
if (s_vga_arg == 2) { s_column_end = data >= ssd1306_lcd.width ? ssd1306_lcd.width - 1 : data; }
|
||||
if (s_vga_arg == 3) { s_cursor_y = (data << 3); }
|
||||
if (s_vga_arg == 4) { s_vga_command = 0; }
|
||||
}
|
||||
else if (s_vga_command == VGA_SET_MODE)
|
||||
{
|
||||
if (s_vga_arg == 1) { s_mode = data; s_vga_command = 0; }
|
||||
if (s_vga_arg == 2) { s_vga_command = 0; }
|
||||
}
|
||||
else if (s_vga_command == VGA_SET_RESOLUTION )
|
||||
{
|
||||
if (s_vga_arg == 1) { s_width = data; }
|
||||
if (s_vga_arg == 2) { s_height = data; }
|
||||
if (s_vga_arg == 3) { s_bpp = data; s_vga_command = 0; }
|
||||
}
|
||||
else if (s_vga_command == VGA_DISPLAY_ON )
|
||||
{
|
||||
__vga_buffer = (uint8_t *) malloc(s_width * s_height * s_bpp / 8);
|
||||
output.init(s_width, s_height, s_bpp);
|
||||
xTaskCreatePinnedToCore(compositeCore, "c", 1024, NULL, 1, NULL, 0);
|
||||
s_vga_command = 0;
|
||||
}
|
||||
s_vga_arg++;
|
||||
}
|
||||
|
||||
static void vga_controller_send_bytes(const uint8_t *buffer, uint16_t len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
ssd1306_intf.send(*buffer);
|
||||
buffer++;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void ssd1306_CompositeVideoInit_esp32(void);
|
||||
void ssd1306_CompositeVideoInit_esp32(void)
|
||||
{
|
||||
ssd1306_intf.spi = 0;
|
||||
ssd1306_intf.start = vga_controller_init;
|
||||
ssd1306_intf.stop = vga_controller_stop;
|
||||
ssd1306_intf.send = vga_controller_send_byte;
|
||||
ssd1306_intf.send_buffer = vga_controller_send_bytes;
|
||||
ssd1306_intf.close = vga_controller_close;
|
||||
}
|
||||
|
||||
void ssd1306_debug_print_vga_buffer_128x64(void (*func)(uint8_t))
|
||||
{
|
||||
for(int y = 0; y < ssd1306_lcd.height; y++)
|
||||
{
|
||||
for(int x = 0; x < ssd1306_lcd.width; x++)
|
||||
{
|
||||
uint8_t color = __vga_buffer[(x >> 3) + y * 16] & (1<< (x&0x07));
|
||||
if (color)
|
||||
{
|
||||
func('#');
|
||||
}
|
||||
else
|
||||
{
|
||||
func(' ');
|
||||
}
|
||||
}
|
||||
func('\n');
|
||||
}
|
||||
func('\n');
|
||||
}
|
||||
|
||||
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t))
|
||||
{
|
||||
ssd1306_debug_print_vga_buffer_128x64(func);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
#include "vga.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE) && defined(ESP32)
|
||||
extern void ssd1306_CompositeVideoInit_esp32(void);
|
||||
void ssd1306_vgaInit()
|
||||
{
|
||||
ssd1306_CompositeVideoInit_esp32();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ssd1306_vgaInit()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2019, Alexey Dynda
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/**
|
||||
* @file vga.h VGA basic data. Do not include this header in your project!!!
|
||||
*/
|
||||
|
||||
#ifndef _SSD1306_VGA_H_
|
||||
#define _SSD1306_VGA_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ssd1306_hal/io.h"
|
||||
|
||||
#if defined(CONFIG_VGA_AVAILABLE) && defined(CONFIG_VGA_ENABLE)
|
||||
|
||||
#ifndef DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
#if defined(__AVR_ATmega328P__)
|
||||
/* TODO: Move defines out of this file */
|
||||
static const uint8_t H_SYNC_PIN = 3;
|
||||
static const uint8_t V_SYNC_PIN = 10;
|
||||
extern volatile uint8_t __vga_buffer[];
|
||||
|
||||
/**
|
||||
* Make ms milliseconds delay. This function has very low precision: 16ms.
|
||||
*
|
||||
* @param ms time in milliseconds
|
||||
*/
|
||||
void ssd1306_vga_delay(uint32_t ms);
|
||||
|
||||
#elif defined(ESP32)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
|
||||
/**
|
||||
* Prints vga buffer in text form using passed callback
|
||||
*
|
||||
* @param func callback to use for printing single character
|
||||
*/
|
||||
void ssd1306_debug_print_vga_buffer(void (*func)(uint8_t));
|
||||
|
||||
/**
|
||||
* Initializes hardware VGA controller
|
||||
* Be careful, this function reinitialized Atmega328p timers.
|
||||
* delay() function will not work after call.
|
||||
*/
|
||||
//void ssd1306_vga_controller_init(void);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void ssd1306_vgaInit(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user