i2c master seems to be working
OLED is now rendering "Supercon" text. Moved several functions to RAM to speed up operation. There is a significant speed hit when executing from Flash on this MCU.
This commit is contained in:
parent
261f5bdfbf
commit
64ce976b97
|
@ -18,7 +18,9 @@
|
|||
|
||||
#include "soft_i2c_master.h"
|
||||
|
||||
|
||||
/* known bugs / limitations:
|
||||
* - there is no ack on address. code always assumes slave is responding.
|
||||
*/
|
||||
#define i2c_init() i2cm_init()
|
||||
#define i2c_start() SetSysClock(SYSCLK_FREQ_USEI2C); i2cm_start()
|
||||
#define i2c_restart() i2cm_restart()
|
||||
|
|
|
@ -19,12 +19,12 @@
|
|||
#include <stdint.h>
|
||||
|
||||
|
||||
#define CYCLES_TO_HI 16
|
||||
#define CYCLES_TO_LO 16
|
||||
#define CYCLES_TO_HI 5 // these settings will result in ~500KHz (32MHz HCLK)
|
||||
#define CYCLES_TO_LO 2
|
||||
|
||||
#define CYCLES_RD 2 // cycles spent in read routine
|
||||
#define CYCLES_EXTRA_WR_HI 2 // extra cycles spent in write routine
|
||||
#define CYCLES_EXTRA_WR_LO 4
|
||||
#define CYCLES_RD 2 // cycles spent in read routine
|
||||
#define CYCLES_WR_HI 2 // extra cycles spent in write routine
|
||||
#define CYCLES_WR_LO 4
|
||||
|
||||
|
||||
#define SDA_PIN 4
|
||||
|
@ -62,18 +62,18 @@ static volatile uint16_t spin;
|
|||
#define bit_delay_hi() spin = delay_hi; while(spin--)
|
||||
#define bit_delay_lo() spin = delay_lo; while(spin--)
|
||||
|
||||
#define rd_delay() spin = delay_hi - CYCLES_RD; while(spin--)
|
||||
#define rd_delay() bit_delay_hi()
|
||||
|
||||
#define wr_delay_hi() spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--)
|
||||
#define wr_delay_lo() spin = delay_lo - CYCLES_EXTRA_WR_LO; while(spin--)
|
||||
#define wr_delay_hi() bit_delay_hi()
|
||||
#define wr_delay_lo() bit_delay_hi() // spin = delay_hi - CYCLES_EXTRA_WR_HI; while(spin--)
|
||||
|
||||
|
||||
|
||||
// re-run init any time the clock speed changes to recalculate delays.
|
||||
void i2cm_init()
|
||||
{
|
||||
uint32_t sysclk;
|
||||
uint32_t cycles;
|
||||
//uint32_t sysclk;
|
||||
//uint32_t cycles;
|
||||
|
||||
// configure GPIO
|
||||
SCL_IN_HI();
|
||||
|
@ -83,13 +83,14 @@ void i2cm_init()
|
|||
SDA_SET_LO();
|
||||
|
||||
// configure timer
|
||||
sysclk = GetSysClock();
|
||||
cycles = sysclk / 500000;
|
||||
//sysclk = GetSysClock();
|
||||
//cycles = sysclk / 500000;
|
||||
|
||||
delay_hi = (cycles - CYCLES_TO_HI - 2) / 4;
|
||||
delay_lo = (cycles - CYCLES_TO_LO - 2) / 4;
|
||||
delay_hi = CYCLES_TO_HI;
|
||||
delay_lo = CYCLES_TO_LO;
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc")))
|
||||
void i2cm_start()
|
||||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
|
@ -98,6 +99,7 @@ void i2cm_start()
|
|||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc")))
|
||||
void i2cm_restart()
|
||||
{
|
||||
SDA_IN_HI(); bit_delay_hi();
|
||||
|
@ -105,6 +107,7 @@ void i2cm_restart()
|
|||
i2cm_start();
|
||||
}
|
||||
|
||||
__attribute__((section(".ramfunc")))
|
||||
void i2cm_stop()
|
||||
{
|
||||
SDA_OUTLO(); bit_delay_lo();
|
||||
|
@ -118,11 +121,13 @@ void i2cm_stop()
|
|||
}
|
||||
|
||||
// returns: data byte
|
||||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_rd(uint8_t ack)
|
||||
{
|
||||
uint8_t x, in = 0;
|
||||
|
||||
SDA_IN_HI();
|
||||
|
||||
for (x = 8; x; x--) {
|
||||
in <<= 1; // clock next bit
|
||||
|
||||
|
@ -142,29 +147,30 @@ uint8_t i2cm_rd(uint8_t ack)
|
|||
SCL_IN_HI(); bit_delay_hi();
|
||||
|
||||
SDA_IN_HI();
|
||||
SCL_OUTLO();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
// returns: possible ack from target
|
||||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_wr(uint8_t dat)
|
||||
{
|
||||
uint8_t x;
|
||||
uint8_t ack;
|
||||
|
||||
SCL_IN_HI();
|
||||
while (!SCL_GET()); // clock stretch
|
||||
SCL_OUTLO();
|
||||
|
||||
for (x = 8; x; x--) {
|
||||
if (dat & 0x80) { SDA_IN_HI(); }
|
||||
else { SDA_OUTLO(); }
|
||||
|
||||
SCL_IN_HI(); wr_delay_hi();
|
||||
while (!SCL_GET()); // clock stretch
|
||||
|
||||
dat <<= 1;
|
||||
|
||||
SCL_OUTLO();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
}
|
||||
|
||||
SDA_IN_HI();
|
||||
|
@ -172,11 +178,12 @@ uint8_t i2cm_wr(uint8_t dat)
|
|||
|
||||
ack = SDA_GET();
|
||||
|
||||
SCL_OUTLO();
|
||||
SCL_OUTLO(); bit_delay_lo();
|
||||
return ack;
|
||||
}
|
||||
|
||||
// use a left-aligned address with this implementation.
|
||||
__attribute__((section(".ramfunc")))
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit)
|
||||
{
|
||||
addr &= ~0x1;
|
||||
|
@ -185,13 +192,13 @@ uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit)
|
|||
}
|
||||
|
||||
|
||||
void i2cm_rdbuf(uint8_t *dat, uint8_t len)
|
||||
void i2cm_rdbuf(uint8_t *dat, uint16_t len)
|
||||
{
|
||||
while (len--) *dat++ = i2cm_rd(len > 0);
|
||||
// i2cm_stop();
|
||||
}
|
||||
|
||||
void i2cm_wrbuf(const uint8_t *dat, uint8_t len)
|
||||
void i2cm_wrbuf(const uint8_t *dat, uint16_t len)
|
||||
{
|
||||
uint8_t nack;
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ uint8_t i2cm_rd(uint8_t ack);
|
|||
uint8_t i2cm_wr(uint8_t dat);
|
||||
uint8_t i2cm_addr(uint8_t addr, uint8_t reading_bit);
|
||||
|
||||
void i2cm_rdbuf(uint8_t *dat, uint8_t len);
|
||||
void i2cm_wrbuf(const uint8_t *dat, uint8_t len);
|
||||
void i2cm_rdbuf(uint8_t *dat, uint16_t len);
|
||||
void i2cm_wrbuf(const uint8_t *dat, uint16_t len);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ extern uint8_t oled_fb[((SSD1306_HEIGHT >> 3) * SSD1306_WIDTH) + 1];
|
|||
|
||||
|
||||
|
||||
#define ssd1306_write(dat, len, cb) i2c_addr(SSD1306_I2C_ADDR, 1); i2c_wrbuf(dat, len); if (cb) ssd1306_cb(0)
|
||||
#define ssd1306_write(dat, len, cb) i2c_addr((SSD1306_I2C_ADDR << 1), 0); i2c_wrbuf(dat, len); if (cb) ssd1306_cb(0)
|
||||
#define ssd1306_idle() 0
|
||||
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
|
||||
// global settings
|
||||
#define OLED_UPDATE_RATE 64 // framerate of OLED; (256*0.75) / OLED_UPDATE_RATE
|
||||
#define OLED_UPDATE_RATE 8 // framerate of OLED; (256*(6/8)) / OLED_UPDATE_RATE; 8 = 24FPS
|
||||
|
||||
// flags
|
||||
#define FLAG_OLED_UPDATE (1 << 0)
|
||||
|
@ -87,6 +87,7 @@ void ch59x_xtal_conf()
|
|||
* trigger an interrupt when bits match a mask. at this time we're not using the RTC
|
||||
* for anything else so putting RTC should suffice for our main tick interrupt.
|
||||
*/
|
||||
__HIGH_CODE
|
||||
void rtc_reset_trig()
|
||||
{
|
||||
sys_safe_access_enable();
|
||||
|
@ -113,6 +114,7 @@ void rtcisr_init()
|
|||
PFIC_EnableIRQ(RTC_IRQn);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void oled_update_done()
|
||||
{
|
||||
int16_t a;
|
||||
|
@ -228,9 +230,10 @@ int main()
|
|||
// configure port-based interrupts (used for ch32sub interrupt)
|
||||
port_intr_init();
|
||||
|
||||
// start up the OLED
|
||||
// start up the OLED and menu system
|
||||
ssd1306fb_set_target(&oled);
|
||||
ssd1306_init(1); // we'll try to init later too, since sometimes they fail
|
||||
menu_stop(0); // lol. yes, this "starts" the "menu" in nametag mode
|
||||
|
||||
// configure main program tick interrupt
|
||||
rtcisr_init();
|
||||
|
@ -289,31 +292,37 @@ void RTC_IRQHandler(void)
|
|||
uptime_sec = (uint8_t)((uptime ) % 60);
|
||||
}
|
||||
|
||||
// render and update RGBLED at 64Hz
|
||||
if ((st_tick & 0x3) == 0x3) {
|
||||
// make sure a valid program is selected
|
||||
if (uconf.ledprog_rgb_idx > (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]))) {
|
||||
uconf.ledprog_rgb_idx = 0;
|
||||
// operations
|
||||
switch (st_tick & 0x7) {
|
||||
case 0:
|
||||
case 3: {
|
||||
// make sure a valid program is selected
|
||||
if (uconf.ledprog_rgb_idx > (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]))) {
|
||||
uconf.ledprog_rgb_idx = 0;
|
||||
}
|
||||
|
||||
// send any rendered data now
|
||||
rgbled_send();
|
||||
|
||||
// defer rendering
|
||||
flags |= FLAG_RGBLED_RUN_PROG;
|
||||
break;
|
||||
}
|
||||
|
||||
// send any rendered data now
|
||||
rgbled_send();
|
||||
|
||||
// defer rendering
|
||||
flags |= FLAG_RGBLED_RUN_PROG;
|
||||
}
|
||||
|
||||
// render and update the oled during non-rgbled frames
|
||||
else {
|
||||
oled_tick++;
|
||||
if (oled_tick >= OLED_UPDATE_RATE) {
|
||||
oled_tick = 0;
|
||||
flags |= FLAG_OLED_UPDATE;
|
||||
case 1: {
|
||||
accel_poll();
|
||||
// no break
|
||||
}
|
||||
default: {
|
||||
oled_tick++;
|
||||
if (oled_tick >= OLED_UPDATE_RATE) {
|
||||
oled_tick = 0;
|
||||
flags |= FLAG_OLED_UPDATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read accelerometer data at 32Hz
|
||||
if ((st_tick & 0x7) == 0x7) {
|
||||
accel_poll();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
*
|
||||
* mostly implemented by true
|
||||
* some functions shamelessly copied and modified from interwebs
|
||||
*
|
||||
* todo:
|
||||
* - new MCU is fast enough to convert entire framebuffer quickly.
|
||||
* it may save time and power to render a standard pixel framebuffer,
|
||||
* then convert. would also make code much cleaner. need to test.
|
||||
*/
|
||||
|
||||
#include "draw_ssd1306.h"
|
||||
|
@ -47,6 +52,7 @@ void ssd1306fb_set_color(uint8_t color)
|
|||
* there are assumptions about pages as well; Y pages will always
|
||||
* start on a boundary.
|
||||
*/
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_rotate(SSD1306 *src, SSD1306 *dst, int8_t rot)
|
||||
{
|
||||
int8_t x, y, nx, ny;
|
||||
|
@ -100,6 +106,7 @@ void ssd1306fb_rotate(SSD1306 *src, SSD1306 *dst, int8_t rot)
|
|||
* draws from data stored in horizontal priority page byte order
|
||||
* (useful for copying between buffers)
|
||||
*/
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_copy(int8_t x, int8_t y, uint8_t width, uint8_t height, const uint8_t *dat)
|
||||
{
|
||||
uint16_t i;
|
||||
|
@ -189,6 +196,7 @@ void ssd1306fb_copy(int8_t x, int8_t y, uint8_t width, uint8_t height, const uin
|
|||
/*
|
||||
* draws from data stored in vertical priority page byte order (why? why not just horizontal? ...)
|
||||
*/
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_raw(int8_t x, int8_t y, uint8_t width, uint8_t height, const uint8_t *dat, uint16_t dat_offset, uint16_t bytes)
|
||||
{
|
||||
uint16_t i;
|
||||
|
@ -280,6 +288,7 @@ void ssd1306fb_draw_raw(int8_t x, int8_t y, uint8_t width, uint8_t height, const
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_pix(uint8_t x, uint8_t y)
|
||||
{
|
||||
uint8_t *fb;
|
||||
|
@ -302,6 +311,7 @@ void ssd1306fb_draw_pix(uint8_t x, uint8_t y)
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_hline(uint8_t x1, uint8_t x2, uint8_t y)
|
||||
{
|
||||
uint8_t t;
|
||||
|
@ -332,6 +342,7 @@ void ssd1306fb_draw_hline(uint8_t x1, uint8_t x2, uint8_t y)
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_vline(uint8_t x, uint8_t y1, uint8_t y2)
|
||||
{
|
||||
uint8_t t;
|
||||
|
@ -407,6 +418,7 @@ void ssd1306fb_draw_vline(uint8_t x, uint8_t y1, uint8_t y2)
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||
{
|
||||
int8_t t;
|
||||
|
@ -453,6 +465,7 @@ void ssd1306fb_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
|||
}
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||
{
|
||||
ssd1306fb_draw_vline(x1, y1 + 1, y2 - 1);
|
||||
|
@ -463,6 +476,7 @@ void ssd1306fb_draw_rect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
|||
|
||||
|
||||
// note: rect fill not working right now, lol
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_rect_fill(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
||||
{
|
||||
uint8_t t;
|
||||
|
@ -476,6 +490,7 @@ void ssd1306fb_draw_rect_fill(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
|
|||
} while (y1++ < y2);
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_draw_circle(int8_t x, int8_t y, uint8_t radius)
|
||||
{
|
||||
int8_t xs = 0;
|
||||
|
@ -508,6 +523,7 @@ void ssd1306fb_draw_circle(int8_t x, int8_t y, uint8_t radius)
|
|||
/*
|
||||
* character string drawing functions draw at the cursor position.
|
||||
*/
|
||||
__HIGH_CODE
|
||||
uint8_t ssd1306fb_get_str_width(const uint8_t *font, const char *str, uint8_t len, int8_t extra_spacing)
|
||||
{
|
||||
uint8_t first = font[FONT_FIRST_CHAR_POS];
|
||||
|
@ -537,6 +553,7 @@ uint8_t ssd1306fb_get_font_height(const uint8_t *font)
|
|||
return font[FONT_HEIGHT_POS];
|
||||
}
|
||||
|
||||
__HIGH_CODE
|
||||
void ssd1306fb_internal_str(const uint8_t *font, const char *str, uint8_t len, int8_t spacing)
|
||||
{
|
||||
const uint8_t height = font[FONT_HEIGHT_POS];
|
||||
|
|
Loading…
Reference in New Issue