123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- /* 7 rows LED bar firmware / library
- * Copyright (C) 2019 asdrea
- *
- * This program is free software: you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later
- * version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <SPI.h>
- #include <string.h>
- #include "charset.h"
- #include "ledbar.h"
- static SPISettings spi_settings(1000000, LSBFIRST, SPI_MODE2);
- // Double buffer ROWSxCOLS bits
- static uint8_t ledbar_framebuf[2][LEDBAR_ROWS][LEDBAR_COLS >> 3];
- static volatile uint8_t cur_buf = 0, swap_buf = 0;
- static inline uint8_t getbuf(ledbar_buf_t b) { return (b == LEDBAR_FRONTBUF ? cur_buf : (1 - cur_buf)); }
- void ledbar_init(void)
- {
- uint8_t i;
- for(i = 0; i < LEDBAR_ROWS; ++i) {
- pinMode(LEDBAR_PIN_ROWS[i], OUTPUT);
- digitalWrite(LEDBAR_PIN_ROWS[i], LOW);
- }
- pinMode(LEDBAR_PIN_STROBE, OUTPUT);
- digitalWrite(LEDBAR_PIN_STROBE, LOW);
- SPI.begin();
- memset(ledbar_framebuf, 0, 2 * LEDBAR_ROWS * (LEDBAR_COLS >> 3));
- // Set timer1 interrupt at ~350Hz
- cli();
- TCCR1A = 0;
- TCCR1B = 0;
- TCNT1 = 0;
- OCR1A = 44; // = 16e6 / (350 * 1024) - 1 (must be <65536)
- TCCR1B |= (1 << WGM12); // turn on CTC mode
- TCCR1B |= (1 << CS12) | (1 << CS10); // Set CS10 and CS12 bits for 1024 prescaler
- TIMSK1 |= (1 << OCIE1A); // Enable timer compare interrupt
- sei();
- }
- void ledbar_wait_vsync(void)
- {
- while(swap_buf);
- }
- void ledbar_swap_buf(void)
- {
- swap_buf = 1;
- }
- void ledbar_clear(ledbar_buf_t buf)
- {
- memset(ledbar_framebuf[getbuf(buf)], 0, LEDBAR_ROWS * (LEDBAR_COLS >> 3));
- }
- #define _LEDBAR_SETCHAR_SETCOL(X) \
- if(b < (8 - X)) { \
- c0 |= ((chbuf[X] >> k) & 0x1) << ((7 - X) - b); \
- } \
- else { \
- c1 |= ((chbuf[X] >> k) & 0x1) << ((15 - X) - b); \
- }
- void ledbar_setchar(ledbar_buf_t buf, int16_t col, uint8_t ch)
- {
- uint8_t i, k, *p;
- uint8_t chbuf[5];
- uint8_t c0 = 0, c1 = 0;
- int8_t block = (col >> 3);
- int8_t b = col - (block << 3);
- uint8_t buf_id = getbuf(buf);
- if(block < -1 || block >= (LEDBAR_COLS >> 3))
- return;
- memcpy_P(chbuf, CHARSET[ch] + i, 5);
- for(i = 0; i < LEDBAR_ROWS; ++i) {
- p = ledbar_framebuf[buf_id][i] + block;
- if(block >= 0)
- c0 = p[0];
- if(block < ((LEDBAR_COLS >> 3) - 1))
- c1 = p[1];
- k = LEDBAR_ROWS - i - 1;
- // Optimize this shit?
- _LEDBAR_SETCHAR_SETCOL(4);
- _LEDBAR_SETCHAR_SETCOL(3);
- _LEDBAR_SETCHAR_SETCOL(2);
- _LEDBAR_SETCHAR_SETCOL(1);
- c0 |= ((chbuf[0] >> k) & 0x1) << (7 - b); // == _LEDBAR_SETCHAR_SETCOL(0)
- if(block >= 0)
- p[0] = c0;
- if(block < ((LEDBAR_COLS >> 3) - 1))
- p[1] = c1;
- }
- }
- void ledbar_settext(ledbar_buf_t buf, int16_t col, const char* text, uint8_t spacing)
- {
- uint16_t i;
- for(i = 0; text[i]; ++i) {
- ledbar_setchar(buf, col, text[i]);
- col += 5 + spacing;
- }
- }
- ISR(TIMER1_COMPA_vect)
- {
- static uint8_t cur_row = LEDBAR_ROWS - 1;
- uint8_t i, rowbuf[LEDBAR_COLS >> 3];
- // Power-off previous row
- digitalWrite(LEDBAR_PIN_ROWS[cur_row++], LOW);
- if(cur_row >= LEDBAR_ROWS) {
- cur_row = 0;
- if(swap_buf) {
- // Swap buffers only on the first row (i.e. sync @50Hz)
- cur_buf = 1 - cur_buf;
- swap_buf = 0;
- }
- }
- // Buffer column data (SPI.transfer() modify the content)
- for(i = 0; i < (LEDBAR_COLS >> 3); ++i)
- rowbuf[i] = ledbar_framebuf[cur_buf][cur_row][(LEDBAR_COLS >> 3) - i - 1];
- // Write column data
- SPI.beginTransaction(spi_settings);
- SPI.transfer(rowbuf, LEDBAR_COLS >> 3);
- SPI.endTransaction();
- // Strobe
- digitalWrite(LEDBAR_PIN_STROBE, HIGH);
- digitalWrite(LEDBAR_PIN_STROBE, LOW);
- // Need a delay here? Glitchy?
- // Power-on current row
- digitalWrite(LEDBAR_PIN_ROWS[cur_row], HIGH);
- }
|