From b6d4e1936e7ab7bdf3f88461ab51888f6b4972e6 Mon Sep 17 00:00:00 2001 From: Joseph Coffland Date: Sat, 22 Jul 2017 00:51:02 -0700 Subject: [PATCH] Write LCD booting screen from AVR bootloader --- src/boot/src/boot.c | 54 ++++++++++++++-------- src/boot/src/lcd.c | 105 +++++++++++++++++++++++++++++++++++++++++++ src/boot/src/lcd.h | 102 +++++++++++++++++++++++++++++++++++++++++ src/py/bbctrl/LCD.py | 4 +- 4 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 src/boot/src/lcd.c create mode 100644 src/boot/src/lcd.h diff --git a/src/boot/src/boot.c b/src/boot/src/boot.c index a0ac310..a2a6c5a 100644 --- a/src/boot/src/boot.c +++ b/src/boot/src/boot.c @@ -28,6 +28,7 @@ #include "boot.h" #include "sp_driver.h" +#include "lcd.h" #include #include @@ -59,6 +60,15 @@ void clock_init() { } +void lcd_splash(uint8_t addr) { + lcd_init(addr); + lcd_goto(addr, 1, 1); + lcd_pgmstr(addr, "Controller booting"); + lcd_goto(addr, 3, 2); + lcd_pgmstr(addr, "Please wait..."); +} + + bool uart_has_char() {return UART_DEVICE.STATUS & USART_RXCIF_bm;} uint8_t uart_recv_char() {return UART_DEVICE.DATA;} @@ -219,26 +229,11 @@ void BlockRead(unsigned size, uint8_t mem, uint32_t *address) { } -int main() { - // Init - clock_init(); - uart_init(); - watchdog_init(); - - // Check for trigger - bool in_bootloader = false; - uint16_t j = INITIAL_WAIT; - while (!in_bootloader && 0 < j--) { - if (uart_has_char()) in_bootloader = uart_recv_char() == CMD_SYNC; - watchdog_reset(); - _delay_ms(1); - } - - // Main bootloader +void bootloader() { uint32_t address = 0; uint16_t i = 0; - while (in_bootloader) { + while (true) { uint8_t val = get_char(); watchdog_reset(); @@ -341,8 +336,8 @@ int main() { break; case CMD_EXIT_BOOTLOADER: - in_bootloader = false; send_char(REPLY_ACK); + return; break; case CMD_PROGRAMMER_TYPE: send_char('S'); break; // serial @@ -435,6 +430,26 @@ int main() { // Wait for any lingering SPM instructions to finish nvm_wait(); } +} + + +int main() { + // Init + clock_init(); + uart_init(); + watchdog_init(); + + // Check for trigger + uint16_t j = INITIAL_WAIT; + while (0 < j--) { + if (uart_has_char() && uart_recv_char() == CMD_SYNC) { + bootloader(); + break; + } + + watchdog_reset(); + _delay_ms(1); + } // Deinit uart_deinit(); @@ -443,6 +458,9 @@ int main() { // Disable further self programming until next reset SP_LockSPM(); + lcd_splash(0x27); + lcd_splash(0x3f); + // Jump to application code asm("jmp 0"); } diff --git a/src/boot/src/lcd.c b/src/boot/src/lcd.c new file mode 100644 index 0000000..7379a2f --- /dev/null +++ b/src/boot/src/lcd.c @@ -0,0 +1,105 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2017 Buildbotics LLC + Copyright (c) 2010 Alex Forencich + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +#include "lcd.h" + +#include +#include + +#include + + +void lcd_init(uint8_t addr) { + // Enable I2C master + TWIC.MASTER.BAUD = 0x9b; // 100 KHz with 32MHz clock + TWIC.MASTER.CTRLA = TWI_MASTER_ENABLE_bm; + TWIC.MASTER.CTRLB = TWI_MASTER_TIMEOUT_DISABLED_gc; + TWIC.MASTER.STATUS |= 1; // Force idle + + _delay_ms(50); + lcd_nibble(addr, 3 << 4); // Home + _delay_ms(50); + lcd_nibble(addr, 3 << 4); // Home + _delay_ms(50); + lcd_nibble(addr, 3 << 4); // Home + lcd_nibble(addr, 2 << 4); // 4-bit + + lcd_write(addr, + LCD_FUNCTION_SET | LCD_2_LINE | LCD_5x8_DOTS | LCD_4_BIT_MODE, 0); + lcd_write(addr, LCD_DISPLAY_CONTROL | LCD_DISPLAY_ON, 0); + lcd_write(addr, LCD_ENTRY_MODE_SET | LCD_ENTRY_SHIFT_INC, 0); + + lcd_write(addr, LCD_CLEAR_DISPLAY, 0); + lcd_write(addr, LCD_RETURN_HOME, 0); +} + + +static void _write_i2c(uint8_t addr, uint8_t data) { + data |= BACKLIGHT_BIT; + + TWIC.MASTER.ADDR = addr << 1; + while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm)) continue; + + TWIC.MASTER.DATA = data; + while (!(TWIC.MASTER.STATUS & TWI_MASTER_WIF_bm)) continue; + + TWIC.MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; + + _delay_us(100); +} + + +void lcd_nibble(uint8_t addr, uint8_t data) { + _write_i2c(addr, data); + _write_i2c(addr, data | ENABLE_BIT); + _delay_us(500); + _write_i2c(addr, data & ~ENABLE_BIT); + _delay_us(100); +} + + +void lcd_write(uint8_t addr, uint8_t cmd, uint8_t flags) { + lcd_nibble(addr, flags | (cmd & 0xf0)); + lcd_nibble(addr, flags | ((cmd << 4) & 0xf0)); +} + + +void lcd_goto(uint8_t addr, uint8_t x, uint8_t y) { + static uint8_t row[] = {0, 64, 20, 84}; + lcd_write(addr, LCD_SET_DDRAM_ADDR | (row[y] + x), 0); +} + + +void lcd_putchar(uint8_t addr, uint8_t c) { + lcd_write(addr, c, REG_SELECT_BIT); +} + + +void lcd_pgmstr(uint8_t addr, const char *s) { + while (*s) lcd_putchar(addr, *s++); +} diff --git a/src/boot/src/lcd.h b/src/boot/src/lcd.h new file mode 100644 index 0000000..29fc616 --- /dev/null +++ b/src/boot/src/lcd.h @@ -0,0 +1,102 @@ +/******************************************************************************\ + + This file is part of the Buildbotics firmware. + + Copyright (c) 2015 - 2017 Buildbotics LLC + Copyright (c) 2010 Alex Forencich + All rights reserved. + + This file ("the software") is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License, + version 2 as published by the Free Software Foundation. You should + have received a copy of the GNU General Public License, version 2 + along with the software. If not, see . + + The software is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the software. If not, see + . + + For information regarding this software email: + "Joseph Coffland" + +\******************************************************************************/ + +#pragma once + +#include + +#include + + +// Control flags +enum { + REG_SELECT_BIT = 1 << 0, + READ_BIT = 1 << 1, + ENABLE_BIT = 1 << 2, + BACKLIGHT_BIT = 1 << 3, +}; + + +// Commands +enum { + LCD_CLEAR_DISPLAY = 1 << 0, + LCD_RETURN_HOME = 1 << 1, + LCD_ENTRY_MODE_SET = 1 << 2, + LCD_DISPLAY_CONTROL = 1 << 3, + LCD_CURSOR_SHIFT = 1 << 4, + LCD_FUNCTION_SET = 1 << 5, + LCD_SET_CGRAM_ADDR = 1 << 6, + LCD_SET_DDRAM_ADDR = 1 << 7, +}; + + +// Entry Mode Set flags +#define LCD_ENTRY_SHIFT_DISPLAY (1 << 0) +#define LCD_ENTRY_SHIFT_INC (1 << 1) +#define LCD_ENTRY_SHIFT_DEC (0 << 1) + + +// Display Control flags +#define LCD_BLINK_ON (1 << 0) +#define LCD_BLINK_OFF (0 << 0) +#define LCD_CURSOR_ON (1 << 1) +#define LCD_CURSOR_OFF (0 << 1) +#define LCD_DISPLAY_ON (1 << 2) +#define LCD_DISPLAY_OFF (0 << 2) + + +// Cursor Shift flags +#define LCD_SHIFT_RIGHT (1 << 2) +#define LCD_SHIFT_LEFT (0 << 2) +#define LCD_SHIFT_DISPLAY (1 << 3) +#define LCD_SHIFT_CURSOR (0 << 3) + + +// Function Set flags +#define LCD_5x11_DOTS (1 << 2) +#define LCD_5x8_DOTS (0 << 2) +#define LCD_2_LINE (1 << 3) +#define LCD_1_LINE (0 << 3) +#define LCD_8_BIT_MODE (1 << 4) +#define LCD_4_BIT_MODE (0 << 4) + + +// Text justification flags +enum { + JUSTIFY_LEFT = 0, + JUSTIFY_RIGHT = 1, + JUSTIFY_CENTER = 2, +}; + + +void lcd_init(uint8_t addr); +void lcd_nibble(uint8_t addr, uint8_t data); +void lcd_write(uint8_t addr, uint8_t cmd, uint8_t flags); +void lcd_goto(uint8_t addr, uint8_t x, uint8_t y); +void lcd_putchar(uint8_t addr, uint8_t c); +void lcd_pgmstr(uint8_t addr, const char *s); diff --git a/src/py/bbctrl/LCD.py b/src/py/bbctrl/LCD.py index b12b2ab..6616baa 100644 --- a/src/py/bbctrl/LCD.py +++ b/src/py/bbctrl/LCD.py @@ -65,8 +65,6 @@ class LCD: self.current_page = 0 self.screen = self.new_screen() - self.set_message('Loading') - # Redraw screen every 5 seconds self.redraw_timer = tornado.ioloop.PeriodicCallback(self._redraw, 5000, self.ctrl.ioloop) @@ -181,4 +179,4 @@ class LCD: self.redraw_timer.stop() self.redraw_timer = None - if self.lcd is not None: self.set_message('Goodbye') + if self.lcd is not None: self.set_message('') -- 2.27.0