From d0300ff457b99509fdac65fb47b1ce645e90591c Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 27 Feb 2017 09:46:05 +0100 Subject: [PATCH 01/12] [ion/device] Add SPI registers Change-Id: I5e91a31e0c4bfc11057714e57e7daad0eba41da3 --- ion/src/device/regs/rcc.h | 1 + ion/src/device/regs/regs.h | 1 + ion/src/device/regs/spi.h | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 ion/src/device/regs/spi.h diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index 805b91341..234c5af93 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -74,6 +74,7 @@ public: class APB1ENR : Register32 { public: REGS_BOOL_FIELD(TIM3EN, 1); + REGS_BOOL_FIELD(SPI3EN, 15); REGS_BOOL_FIELD(PWREN, 28); }; diff --git a/ion/src/device/regs/regs.h b/ion/src/device/regs/regs.h index 9375e1ed7..5a337cb39 100644 --- a/ion/src/device/regs/regs.h +++ b/ion/src/device/regs/regs.h @@ -13,6 +13,7 @@ #include "rcc.h" #include "rng.h" #include "sdio.h" +#include "spi.h" #include "syscfg.h" #include "tim.h" diff --git a/ion/src/device/regs/spi.h b/ion/src/device/regs/spi.h new file mode 100644 index 000000000..a817a1371 --- /dev/null +++ b/ion/src/device/regs/spi.h @@ -0,0 +1,35 @@ +#ifndef REGS_SPI_H +#define REGS_SPI_H + +#include "register.h" + +class SPI { +public: + class CR1 : Register16 { + public: + REGS_BOOL_FIELD(SPE, 6); + REGS_BOOL_FIELD(LSBFIRST, 7); + REGS_BOOL_FIELD(SSI, 8); + REGS_BOOL_FIELD(SSM, 9); + }; + class SR : Register16 { + public: + REGS_BOOL_FIELD(RXNE, 0); + REGS_BOOL_FIELD(TXE, 1); + }; + class DR : public Register16 { + }; + + constexpr SPI(int i) : m_index(i) {} + constexpr operator int() const { return m_index; } + REGS_REGISTER_AT(CR1, 0x00); + REGS_REGISTER_AT(SR, 0x08); + REGS_REGISTER_AT(DR, 0x0C); +private: + constexpr uint32_t Base() const { + return ((uint32_t []){0x40013000, 0x40003800, 0x40003C00})[m_index-1]; + }; + int m_index; +}; + +#endif From ba2b03bbc321ad4a217f4e73d70a382c4c1ab648 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 27 Feb 2017 09:48:11 +0100 Subject: [PATCH 02/12] [apps] Add a lowlevel test app Change-Id: Id217736cfd39f9994e9d0b4325a52cd63d4a7460 --- apps/hwtest/lowlevel/Makefile | 5 + apps/hwtest/lowlevel/lowlevel.cpp | 177 ++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 apps/hwtest/lowlevel/Makefile create mode 100644 apps/hwtest/lowlevel/lowlevel.cpp diff --git a/apps/hwtest/lowlevel/Makefile b/apps/hwtest/lowlevel/Makefile new file mode 100644 index 000000000..85e1b6960 --- /dev/null +++ b/apps/hwtest/lowlevel/Makefile @@ -0,0 +1,5 @@ +objs += $(addprefix apps/hwtest/lowlevel/,\ + lowlevel.o \ +) + +apps/hwtest/lowlevel/lowlevel.o: SFLAGS += -O3 diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp new file mode 100644 index 000000000..d825c243a --- /dev/null +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -0,0 +1,177 @@ +#include + +#include "../../../ion/src/device/regs/regs.h" + +// SDIOCK -> SPI2_MOSI +// SDIO_D2 -> SPI3_CLK == PC10 +// SDIO_D0 -> SPI3_MISO = PB4 +// SDIO_D3 -> SPI3_MOSI = PB5 +// +// + +// On SD card, from left to right +// D1 - D0 - .... - D3 - D2 +// X - MISO - .... - MOSI - CLK + +// On Rpi, from top to bottom +// MOSI 19 +// MISO 21 +// CLK 23 +// GND 25 +constexpr SPI spiPort = SPI(3); + +void init_spi_port() { + RCC.APB1ENR()->setSPI3EN(true); + + GPIOB.MODER()->setMode(4, GPIO::MODER::Mode::AlternateFunction); + GPIOB.MODER()->setMode(5, GPIO::MODER::Mode::AlternateFunction); + GPIOC.MODER()->setMode(10, GPIO::MODER::Mode::AlternateFunction); + + GPIOB.AFR()->setAlternateFunction(4, GPIO::AFR::AlternateFunction::AF6); + GPIOB.AFR()->setAlternateFunction(5, GPIO::AFR::AlternateFunction::AF6); + GPIOC.AFR()->setAlternateFunction(10, GPIO::AFR::AlternateFunction::AF6); + + spiPort.CR1()->setSPE(true); + + // We don't use a CS wire + spiPort.CR1()->setSSM(true); + spiPort.CR1()->setSSI(0); +} + +char spi_read_char() { + while (spiPort.SR()->getRXNE() == 0) { + } + return (char)spiPort.DR()->get(); +} + +void spi_write_char(char c) { + spiPort.DR()->set(c); + while (spiPort.SR()->getTXE() == 0) { + } +} + +bool readLine(char * buffer, int bufferSize) { + char * endBuffer = buffer + bufferSize - 1; + while (true) { + *buffer = spi_read_char(); + if (*buffer == NULL) { + /* Time for a comment : + * - Building DEBUG=0 might make the device fast enough + * - Reading on the HOST... ALSO sends data to the device !! + * So we were being overflowed with zeroes here... */ + continue; + } + if (*buffer == '\n') { + break; + } + buffer++; + if (buffer == endBuffer) { + return false; + } + } + *buffer = 0; + return true; +} + +void reply(const char * buffer) { + while (*buffer != NULL) { + spi_write_char(*buffer); + buffer++; + } + spi_write_char('\n'); + spi_write_char(0); +} + +typedef void (*CommandFunction)(const char * input); + +void command_ping(const char * input); +void command_mcu_serial(const char * input); + +class CommandHandler { +public: + constexpr CommandHandler(const char * name, CommandFunction function) : + m_name(name), m_function(function) {} + bool valid() const; + bool handle(const char * command) const; +private: + bool matches(const char * command) const; + const char * m_name; + CommandFunction m_function; +}; + +bool CommandHandler::valid() const { + return (m_name != nullptr && m_function != nullptr); +} + +bool CommandHandler::handle(const char * command) const { + if (matches(command)) { + m_function(command); + return true; + } + return false; +} + +bool CommandHandler::matches(const char * command) const { + const char * c = command; + const char * n = m_name; + while (true) { + if (*c != *n) { + return false; + } + if (*n == NULL) { + if (*c == NULL || *c == '=') { + return true; + } + } + c++; + n++; + } +} + +class CommandList { +public: + constexpr CommandList(const CommandHandler * handlers) : m_handlers(handlers) {} + void dispatch(const char * command) const; +private: + const CommandHandler * m_handlers; +}; + +void CommandList::dispatch(const char * command) const { + const CommandHandler * handler = m_handlers; + while (handler->valid()) { + if (handler->handle(command)) { + return; + } + handler++; + } + reply("NOT_FOUND"); +} + +constexpr CommandHandler handles[] = { + CommandHandler("PING", command_ping), + CommandHandler("MCU_SERIAL", command_mcu_serial), + CommandHandler(nullptr, nullptr) +}; + +constexpr const CommandList sCommandList = CommandList(handles); + +void command_ping(const char * input) { + reply("PONG"); +} + +void command_mcu_serial(const char * input) { + reply("UNKNOWN"); +} + +constexpr int kMaxCommandLength = 255; + +void ion_app() { + init_spi_port(); + char command[kMaxCommandLength]; + while (true) { + if (readLine(command, kMaxCommandLength)) { + sCommandList.dispatch(command); + } + } +} + From 8d5cd4b939f31a1b1792d84858a204716561c6b1 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 27 Feb 2017 11:29:13 +0100 Subject: [PATCH 03/12] [ion/device] Add USART register Change-Id: I4883a5bd5cd1092106729641e0bda051c6a7240c --- ion/src/device/regs/rcc.h | 1 + ion/src/device/regs/regs.h | 1 + ion/src/device/regs/usart.h | 50 +++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 ion/src/device/regs/usart.h diff --git a/ion/src/device/regs/rcc.h b/ion/src/device/regs/rcc.h index 234c5af93..561ba9f41 100644 --- a/ion/src/device/regs/rcc.h +++ b/ion/src/device/regs/rcc.h @@ -82,6 +82,7 @@ public: public: using Register32::Register32; REGS_BOOL_FIELD(TIM1EN, 0); + REGS_BOOL_FIELD(USART1EN, 4); REGS_BOOL_FIELD(ADC1EN, 8); REGS_BOOL_FIELD(SDIOEN, 11); REGS_BOOL_FIELD(SYSCFGEN, 14); diff --git a/ion/src/device/regs/regs.h b/ion/src/device/regs/regs.h index 5a337cb39..3fe399ad0 100644 --- a/ion/src/device/regs/regs.h +++ b/ion/src/device/regs/regs.h @@ -16,5 +16,6 @@ #include "spi.h" #include "syscfg.h" #include "tim.h" +#include "usart.h" #endif diff --git a/ion/src/device/regs/usart.h b/ion/src/device/regs/usart.h new file mode 100644 index 000000000..cb454c2d6 --- /dev/null +++ b/ion/src/device/regs/usart.h @@ -0,0 +1,50 @@ +#ifndef REGS_USART_H +#define REGS_USART_H + +#include "register.h" + +class USART { +public: + class SR : Register32 { + public: + REGS_BOOL_FIELD(RXNE, 5); + REGS_BOOL_FIELD(TXE, 7); + }; + + class DR : Register32 { + public: + uint16_t get() volatile { + return (uint16_t)getBitRange(8, 0); + } + void set(uint16_t v) volatile { + setBitRange(8, 0, v); + } + }; + + class BRR : Register32 { + public: + REGS_FIELD(DIV_FRAC, uint8_t, 3, 0); + REGS_FIELD(DIV_MANTISSA, uint16_t, 15, 4); + }; + + class CR1 : Register32 { + public: + REGS_BOOL_FIELD(UE, 13); + REGS_BOOL_FIELD(TE, 3); + REGS_BOOL_FIELD(RE, 2); + }; + + constexpr USART(int i) : m_index(i) {} + constexpr operator int() const { return m_index; } + REGS_REGISTER_AT(SR, 0x00); + REGS_REGISTER_AT(DR, 0x04); + REGS_REGISTER_AT(BRR, 0x08); + REGS_REGISTER_AT(CR1, 0x0C); +private: + constexpr uint32_t Base() const { + return ((uint32_t []){0x40011000, 0x40004400, 0x40004800})[m_index-1]; + }; + int m_index; +}; + +#endif From 257f81d4d29e1768486e47b46b5beb364b50c36a Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 27 Feb 2017 11:30:23 +0100 Subject: [PATCH 04/12] [apps/hwtest] The lowlevel test uses the UART Change-Id: I78dabe99abc10667666ee926d886a7c7828b4cd3 --- apps/hwtest/lowlevel/lowlevel.cpp | 78 +++++++++++++++---------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp index d825c243a..af3601926 100644 --- a/apps/hwtest/lowlevel/lowlevel.cpp +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -2,58 +2,58 @@ #include "../../../ion/src/device/regs/regs.h" -// SDIOCK -> SPI2_MOSI -// SDIO_D2 -> SPI3_CLK == PC10 -// SDIO_D0 -> SPI3_MISO = PB4 -// SDIO_D3 -> SPI3_MOSI = PB5 -// -// - -// On SD card, from left to right -// D1 - D0 - .... - D3 - D2 -// X - MISO - .... - MOSI - CLK +// PB3 = UART1_RX = SWO +// PB6 = UART1_TX = QuadSPI NCS // On Rpi, from top to bottom -// MOSI 19 -// MISO 21 -// CLK 23 -// GND 25 -constexpr SPI spiPort = SPI(3); +// 6 = GND +// 8 = TX +// 10 = RX -void init_spi_port() { - RCC.APB1ENR()->setSPI3EN(true); +constexpr USART uartPort = USART(1); - GPIOB.MODER()->setMode(4, GPIO::MODER::Mode::AlternateFunction); - GPIOB.MODER()->setMode(5, GPIO::MODER::Mode::AlternateFunction); - GPIOC.MODER()->setMode(10, GPIO::MODER::Mode::AlternateFunction); +void init_uart_port() { + RCC.APB2ENR()->setUSART1EN(true); - GPIOB.AFR()->setAlternateFunction(4, GPIO::AFR::AlternateFunction::AF6); - GPIOB.AFR()->setAlternateFunction(5, GPIO::AFR::AlternateFunction::AF6); - GPIOC.AFR()->setAlternateFunction(10, GPIO::AFR::AlternateFunction::AF6); + GPIOB.MODER()->setMode(3, GPIO::MODER::Mode::AlternateFunction); + GPIOB.MODER()->setMode(6, GPIO::MODER::Mode::AlternateFunction); - spiPort.CR1()->setSPE(true); + GPIOB.AFR()->setAlternateFunction(3, GPIO::AFR::AlternateFunction::AF7); + GPIOB.AFR()->setAlternateFunction(6, GPIO::AFR::AlternateFunction::AF7); - // We don't use a CS wire - spiPort.CR1()->setSSM(true); - spiPort.CR1()->setSSI(0); + uartPort.CR1()->setUE(true); + uartPort.CR1()->setTE(true); + uartPort.CR1()->setRE(true); + + // Set the Baud rate + // base clock = 16 MHz + // Baud rate = fAPB2/(16*USARTDIV) + // USARTDIV = 104.16667 + // + // DIV_Fraction = 16*0.16666667 + // = 2.666667 -> 3 + // DIV_Mantissa = 104 = 0x68 + // USART_BRR = 0x683 + uartPort.BRR()->setDIV_FRAC(3); + uartPort.BRR()->setDIV_MANTISSA(104); } -char spi_read_char() { - while (spiPort.SR()->getRXNE() == 0) { +char uart_read_char() { + while (uartPort.SR()->getRXNE() == 0) { } - return (char)spiPort.DR()->get(); + return (char)uartPort.DR()->get(); } -void spi_write_char(char c) { - spiPort.DR()->set(c); - while (spiPort.SR()->getTXE() == 0) { +void uart_write_char(char c) { + while (uartPort.SR()->getTXE() == 0) { } + uartPort.DR()->set(c); } bool readLine(char * buffer, int bufferSize) { char * endBuffer = buffer + bufferSize - 1; while (true) { - *buffer = spi_read_char(); + *buffer = uart_read_char(); if (*buffer == NULL) { /* Time for a comment : * - Building DEBUG=0 might make the device fast enough @@ -61,7 +61,7 @@ bool readLine(char * buffer, int bufferSize) { * So we were being overflowed with zeroes here... */ continue; } - if (*buffer == '\n') { + if (*buffer == '\r') { break; } buffer++; @@ -75,11 +75,11 @@ bool readLine(char * buffer, int bufferSize) { void reply(const char * buffer) { while (*buffer != NULL) { - spi_write_char(*buffer); + uart_write_char(*buffer); buffer++; } - spi_write_char('\n'); - spi_write_char(0); + uart_write_char('\r'); + uart_write_char('\n'); } typedef void (*CommandFunction)(const char * input); @@ -166,7 +166,7 @@ void command_mcu_serial(const char * input) { constexpr int kMaxCommandLength = 255; void ion_app() { - init_spi_port(); + init_uart_port(); char command[kMaxCommandLength]; while (true) { if (readLine(command, kMaxCommandLength)) { From 59c35f7705a364369c5e52a86fc315e98bc9ad29 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 27 Feb 2017 13:25:19 +0100 Subject: [PATCH 05/12] [apps/hwtest] Blink the LED from the lowlevel test Change-Id: I64425caf00b063b4a86f6eaa089fef6995d93ebd --- apps/hwtest/lowlevel/lowlevel.cpp | 59 +++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp index af3601926..016266635 100644 --- a/apps/hwtest/lowlevel/lowlevel.cpp +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -1,4 +1,5 @@ #include +#include #include "../../../ion/src/device/regs/regs.h" @@ -105,7 +106,12 @@ bool CommandHandler::valid() const { bool CommandHandler::handle(const char * command) const { if (matches(command)) { - m_function(command); + size_t nameLength = strlen(m_name); + if (command[nameLength] == '=') { + m_function(command+nameLength+1); // Skip the "Equal character" + } else { + m_function(nullptr); + } return true; } return false; @@ -115,14 +121,14 @@ bool CommandHandler::matches(const char * command) const { const char * c = command; const char * n = m_name; while (true) { - if (*c != *n) { - return false; - } if (*n == NULL) { if (*c == NULL || *c == '=') { return true; } } + if (*c != *n) { + return false; + } c++; n++; } @@ -147,13 +153,7 @@ void CommandList::dispatch(const char * command) const { reply("NOT_FOUND"); } -constexpr CommandHandler handles[] = { - CommandHandler("PING", command_ping), - CommandHandler("MCU_SERIAL", command_mcu_serial), - CommandHandler(nullptr, nullptr) -}; -constexpr const CommandList sCommandList = CommandList(handles); void command_ping(const char * input) { reply("PONG"); @@ -163,6 +163,45 @@ void command_mcu_serial(const char * input) { reply("UNKNOWN"); } + +static inline int8_t hexChar(char c) { + if (c >= '0' && c <= '9') { + return (c - '0'); + } + if (c >= 'A' && c <= 'F') { + return (c - 'A') + 0xA; + } + return -1; +} +static inline bool isHex(char c) { return hexChar(c) >= 0; } +static inline uint32_t hexNumber(const char * s) { + uint32_t result = 0; + while (*s != NULL) { + result = (result << 4) | hexChar(*s++); + } + return result; +} + +void command_led(const char * input) { + // Input must be of the form "0xAABBCC" + if (input == nullptr || input[0] != '0' || input[1] != 'x' || !isHex(input[2]) ||!isHex(input[3]) || !isHex(input[4]) || !isHex(input[5]) || !isHex(input[6]) || !isHex(input[7]) || input[8] != NULL) { + reply("SYNTAX_ERROR"); + return; + } + uint32_t hexColor = hexNumber(input+2); + KDColor ledColor = KDColor::RGB24(hexColor); + Ion::LED::setColor(ledColor); + reply("OK"); +} + +constexpr CommandHandler handles[] = { + CommandHandler("PING", command_ping), + CommandHandler("MCU_SERIAL", command_mcu_serial), + CommandHandler("LED", command_led), + CommandHandler(nullptr, nullptr) +}; +constexpr const CommandList sCommandList = CommandList(handles); + constexpr int kMaxCommandLength = 255; void ion_app() { From bca8a6fd862753e358ef5ae546beceac533cc337 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Mon, 27 Feb 2017 14:13:19 +0100 Subject: [PATCH 06/12] [ion] Add a console facility Change-Id: I34b406ae8589fdd2a5d6b826b34ac411359b58dc --- apps/hwtest/lowlevel/lowlevel.cpp | 98 +++---------------------------- ion/include/ion.h | 1 + ion/include/ion/console.h | 15 +++++ ion/src/device/Makefile | 1 + ion/src/device/console.cpp | 98 +++++++++++++++++++++++++++++++ ion/src/device/console.h | 31 ++++++++++ ion/src/device/device.cpp | 2 + 7 files changed, 155 insertions(+), 91 deletions(-) create mode 100644 ion/include/ion/console.h create mode 100644 ion/src/device/console.cpp create mode 100644 ion/src/device/console.h diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp index 016266635..40ade73a9 100644 --- a/apps/hwtest/lowlevel/lowlevel.cpp +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -1,88 +1,6 @@ #include #include -#include "../../../ion/src/device/regs/regs.h" - -// PB3 = UART1_RX = SWO -// PB6 = UART1_TX = QuadSPI NCS - -// On Rpi, from top to bottom -// 6 = GND -// 8 = TX -// 10 = RX - -constexpr USART uartPort = USART(1); - -void init_uart_port() { - RCC.APB2ENR()->setUSART1EN(true); - - GPIOB.MODER()->setMode(3, GPIO::MODER::Mode::AlternateFunction); - GPIOB.MODER()->setMode(6, GPIO::MODER::Mode::AlternateFunction); - - GPIOB.AFR()->setAlternateFunction(3, GPIO::AFR::AlternateFunction::AF7); - GPIOB.AFR()->setAlternateFunction(6, GPIO::AFR::AlternateFunction::AF7); - - uartPort.CR1()->setUE(true); - uartPort.CR1()->setTE(true); - uartPort.CR1()->setRE(true); - - // Set the Baud rate - // base clock = 16 MHz - // Baud rate = fAPB2/(16*USARTDIV) - // USARTDIV = 104.16667 - // - // DIV_Fraction = 16*0.16666667 - // = 2.666667 -> 3 - // DIV_Mantissa = 104 = 0x68 - // USART_BRR = 0x683 - uartPort.BRR()->setDIV_FRAC(3); - uartPort.BRR()->setDIV_MANTISSA(104); -} - -char uart_read_char() { - while (uartPort.SR()->getRXNE() == 0) { - } - return (char)uartPort.DR()->get(); -} - -void uart_write_char(char c) { - while (uartPort.SR()->getTXE() == 0) { - } - uartPort.DR()->set(c); -} - -bool readLine(char * buffer, int bufferSize) { - char * endBuffer = buffer + bufferSize - 1; - while (true) { - *buffer = uart_read_char(); - if (*buffer == NULL) { - /* Time for a comment : - * - Building DEBUG=0 might make the device fast enough - * - Reading on the HOST... ALSO sends data to the device !! - * So we were being overflowed with zeroes here... */ - continue; - } - if (*buffer == '\r') { - break; - } - buffer++; - if (buffer == endBuffer) { - return false; - } - } - *buffer = 0; - return true; -} - -void reply(const char * buffer) { - while (*buffer != NULL) { - uart_write_char(*buffer); - buffer++; - } - uart_write_char('\r'); - uart_write_char('\n'); -} - typedef void (*CommandFunction)(const char * input); void command_ping(const char * input); @@ -150,17 +68,17 @@ void CommandList::dispatch(const char * command) const { } handler++; } - reply("NOT_FOUND"); + Ion::Console::writeLine("NOT_FOUND"); } void command_ping(const char * input) { - reply("PONG"); + Ion::Console::writeLine("PONG"); } void command_mcu_serial(const char * input) { - reply("UNKNOWN"); + Ion::Console::writeLine("UNKNOWN"); } @@ -185,13 +103,13 @@ static inline uint32_t hexNumber(const char * s) { void command_led(const char * input) { // Input must be of the form "0xAABBCC" if (input == nullptr || input[0] != '0' || input[1] != 'x' || !isHex(input[2]) ||!isHex(input[3]) || !isHex(input[4]) || !isHex(input[5]) || !isHex(input[6]) || !isHex(input[7]) || input[8] != NULL) { - reply("SYNTAX_ERROR"); + Ion::Console::writeLine("SYNTAX_ERROR"); return; } uint32_t hexColor = hexNumber(input+2); KDColor ledColor = KDColor::RGB24(hexColor); Ion::LED::setColor(ledColor); - reply("OK"); + Ion::Console::writeLine("OK"); } constexpr CommandHandler handles[] = { @@ -205,12 +123,10 @@ constexpr const CommandList sCommandList = CommandList(handles); constexpr int kMaxCommandLength = 255; void ion_app() { - init_uart_port(); char command[kMaxCommandLength]; while (true) { - if (readLine(command, kMaxCommandLength)) { - sCommandList.dispatch(command); - } + Ion::Console::readLine(command, kMaxCommandLength); + sCommandList.dispatch(command); } } diff --git a/ion/include/ion.h b/ion/include/ion.h index 3c7b281ad..d15dbb4fe 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include diff --git a/ion/include/ion/console.h b/ion/include/ion/console.h new file mode 100644 index 000000000..4f9600999 --- /dev/null +++ b/ion/include/ion/console.h @@ -0,0 +1,15 @@ +#ifndef ION_CONSOLE_H +#define ION_CONSOLE_H + +namespace Ion { +namespace Console { + +// The lines are NULL-terminated + +void writeLine(const char * line); +void readLine(char * line, int maxLineLength); + +} +} + +#endif diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index 986970daf..230131df6 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -7,6 +7,7 @@ objs += $(addprefix ion/src/shared/, \ objs += $(addprefix ion/src/device/, \ backlight.o \ battery.o\ + console.o \ device.o\ display.o\ keyboard.o\ diff --git a/ion/src/device/console.cpp b/ion/src/device/console.cpp new file mode 100644 index 000000000..febd68445 --- /dev/null +++ b/ion/src/device/console.cpp @@ -0,0 +1,98 @@ +#include +#include "console.h" + +/* This file implements a serial console. + * We use a 9600 8N1 serial port */ + +namespace Ion { +namespace Console { + +void writeLine(const char * line) { + while (*line != NULL) { + Device::sendChar(*line++); + } + Device::sendChar('\r'); + Device::sendChar('\n'); +} + +void readLine(char * line, int maxLineLength) { + if (maxLineLength <= 0) { + return; + } + char * cursor = line; + char * last = line+maxLineLength-1; + while (true) { + *cursor = Device::recvChar(); + if (*cursor == '\r' || cursor == last) { + *cursor = 0; + return; + } + cursor++; + } +} +/* + + lastChar + + char c = Device::recvChar(); + + char * lineEnd = line + maxLineLength; + + while (line < lineEnd) { + *line++ = Device::recvChar(); + if (*line == '\r') { + break; + } + } + *line = 0; +} +*/ + +} +} + +namespace Ion { +namespace Console { +namespace Device { + +void init() { + RCC.APB2ENR()->setUSART1EN(true); + + GPIOB.MODER()->setMode(3, GPIO::MODER::Mode::AlternateFunction); + GPIOB.MODER()->setMode(6, GPIO::MODER::Mode::AlternateFunction); + + GPIOB.AFR()->setAlternateFunction(3, GPIO::AFR::AlternateFunction::AF7); + GPIOB.AFR()->setAlternateFunction(6, GPIO::AFR::AlternateFunction::AF7); + + UARTPort.CR1()->setUE(true); + UARTPort.CR1()->setTE(true); + UARTPort.CR1()->setRE(true); + + // Set the Baud rate + // base clock = 16 MHz + // Baud rate = fAPB2/(16*USARTDIV) + // USARTDIV = 104.16667 + // + // DIV_Fraction = 16*0.16666667 + // = 2.666667 -> 3 + // DIV_Mantissa = 104 = 0x68 + // USART_BRR = 0x683 + UARTPort.BRR()->setDIV_FRAC(3); + UARTPort.BRR()->setDIV_MANTISSA(104); +} + +char recvChar() { + while (UARTPort.SR()->getRXNE() == 0) { + } + return (char)UARTPort.DR()->get(); +} + +void sendChar(char c) { + while (UARTPort.SR()->getTXE() == 0) { + } + UARTPort.DR()->set(c); +} + +} +} +} diff --git a/ion/src/device/console.h b/ion/src/device/console.h new file mode 100644 index 000000000..107fdf5ce --- /dev/null +++ b/ion/src/device/console.h @@ -0,0 +1,31 @@ +#ifndef ION_DEVICE_CONSOLE_H +#define ION_DEVICE_CONSOLE_H + +#include +#include "regs/regs.h" + +namespace Ion { +namespace Console { +namespace Device { + +/* Pin | Role | Mode + * -----+-------------------+-------------------- + * PC11 | UART1 RX | Alternate Function + * PD8 | UART1 TX | Alternate Function + */ + +void init(); +void shutdown(); + +constexpr USART UARTPort = USART(1); +constexpr static GPIOPin RxPin = GPIOPin(GPIOB, 14); +constexpr static GPIOPin TxPin = GPIOPin(GPIOE, 9); + +void sendChar(char c); +char recvChar(); + +} +} +} + +#endif diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index a71efd04f..e9a900932 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -10,6 +10,7 @@ extern "C" { #include "battery.h" #include "sd_card.h" #include "backlight.h" +#include "console.h" #define USE_SD_CARD 0 @@ -85,6 +86,7 @@ void initPeripherals() { #if USE_SD_CARD SDCard::Device::init(); #endif + Console::Device::init(); } void shutdownPeripherals() { From 78b947a6cc522a223a13e271ca7ce9f21e524ca0 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 28 Feb 2017 18:24:23 +0100 Subject: [PATCH 07/12] [ion/device] Use the proper ADC channel Change-Id: I6dd4245cc4e8c8d0fc5ffd1fa53857e7774c5515 --- ion/src/device/battery.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ion/src/device/battery.cpp b/ion/src/device/battery.cpp index 6f66d20c4..02a5fab94 100644 --- a/ion/src/device/battery.cpp +++ b/ion/src/device/battery.cpp @@ -50,6 +50,11 @@ void init() { // Step 2 - Enable the ADC RCC.APB2ENR()->setADC1EN(true); ADC.CR2()->setADON(true); + + // Configure the ADC channel + ADC.SQR1()->setL(0); // Always sample the same channel + ADC.SQR3()->setSQ1(ADCChannel); + ADC.SMPR()->setSamplingTime(ADCChannel, ADC::SMPR::SamplingTime::Cycles480); // Use the max sampling time } void shutdown() { From 1b893ac4ee28644338ab55a3bc9221ab67619386 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 28 Feb 2017 18:24:51 +0100 Subject: [PATCH 08/12] [apps/hwtest] Add ADC and BACKLIGHT commands to the lowlevel test Change-Id: I29085da31be739fc52a2be4a18e12a3e5aa49015 --- apps/hwtest/lowlevel/lowlevel.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp index 40ade73a9..8e1a8fd80 100644 --- a/apps/hwtest/lowlevel/lowlevel.cpp +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -1,5 +1,6 @@ #include #include +#include typedef void (*CommandFunction)(const char * input); @@ -112,10 +113,32 @@ void command_led(const char * input) { Ion::Console::writeLine("OK"); } +void command_backlight(const char * input) { + // Input must be of the form "0xAA" + if (input == nullptr || input[0] != '0' || input[1] != 'x' || !isHex(input[2]) ||!isHex(input[3]) || input[4] != NULL) { + Ion::Console::writeLine("SYNTAX_ERROR"); + return; + } + uint32_t brightness = hexNumber(input+2); + Ion::Backlight::setBrightness(brightness); + Ion::Console::writeLine("OK"); +} + +void command_adc(const char * input) { + float result = Ion::Battery::voltage(); + constexpr int precision = 8; + constexpr int bufferSize = Poincare::Complex::bufferSizeForFloatsWithPrecision(precision); + char responseBuffer[bufferSize+4] = {'A', 'D', 'C', '='}; // ADC= + Poincare::Complex::convertFloatToText(result, responseBuffer+4, bufferSize, precision); + Ion::Console::writeLine(responseBuffer); +} + constexpr CommandHandler handles[] = { CommandHandler("PING", command_ping), CommandHandler("MCU_SERIAL", command_mcu_serial), CommandHandler("LED", command_led), + CommandHandler("BACKLIGHT", command_backlight), + CommandHandler("ADC", command_adc), CommandHandler(nullptr, nullptr) }; constexpr const CommandList sCommandList = CommandList(handles); From eaeed82eeaa47672ecc76ebbd2be3e47029ef5b2 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 28 Feb 2017 18:56:04 +0100 Subject: [PATCH 09/12] [ion] Add a Ion::serialNumber function Change-Id: Ib2dd1d9187936f5c044bbcbc21dc7164fe6e9822 --- ion/include/ion.h | 2 ++ ion/src/device/device.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/ion/include/ion.h b/ion/include/ion.h index d15dbb4fe..800be4efe 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -27,6 +27,8 @@ namespace Ion { void msleep(long ms); void usleep(long us); +const char * serialNumber(); + /* CAUTION: This is a complete reset! */ void reset(); diff --git a/ion/src/device/device.cpp b/ion/src/device/device.cpp index e9a900932..acee35f53 100644 --- a/ion/src/device/device.cpp +++ b/ion/src/device/device.cpp @@ -46,6 +46,27 @@ void Ion::reset() { CM4.AIRCR()->requestReset(); } +static inline char hex(uint8_t d) { + if (d > 9) { + return 'A'+d; + } + return '0'+d; +} + +const char * Ion::serialNumber() { + static char serialNumber[25] = {0}; + if (serialNumber[0] == 0) { + uint8_t * rawUniqueID = (uint8_t *)0x1FFF7A10; + for (int i=0; i<24; i++) { + uint8_t d = *rawUniqueID++; + serialNumber[2*i] = hex(d & 0xF); + serialNumber[2*i+1] = hex(d >> 4); + } + serialNumber[24] = 0; + } + return serialNumber; +} + // Private Ion::Device methods namespace Ion { From b44bad3b928bc589649afcf5f825d804a4ef24c6 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Tue, 28 Feb 2017 18:56:21 +0100 Subject: [PATCH 10/12] [apps/hwtest] Proper MCU_SERIAL command Change-Id: I485bd67fa464a541a89d2c1c878b41a3328bed88 --- apps/hwtest/lowlevel/lowlevel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp index 8e1a8fd80..15fbaac5a 100644 --- a/apps/hwtest/lowlevel/lowlevel.cpp +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -79,10 +79,11 @@ void command_ping(const char * input) { } void command_mcu_serial(const char * input) { - Ion::Console::writeLine("UNKNOWN"); + char response[11+24+1] = {'M', 'C', 'U', '_', 'S', 'E', 'R', 'I', 'A', 'L', '=', 0}; + strlcpy(response+11, Ion::serialNumber(), 25); + Ion::Console::writeLine(response); } - static inline int8_t hexChar(char c) { if (c >= '0' && c <= '9') { return (c - '0'); From 09518c4a0b3943383610a12245d620499bf234c9 Mon Sep 17 00:00:00 2001 From: Romain Goyet Date: Wed, 1 Mar 2017 10:04:41 +0100 Subject: [PATCH 11/12] [apps/hwtest] Add CHARGE and KEYBOARD commands to lowlevel test Change-Id: Ifd3d4c6b0e69c1a5cfbdbff62c6c5f370ecd3dc9 --- apps/hwtest/lowlevel/lowlevel.cpp | 45 ++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/hwtest/lowlevel/lowlevel.cpp b/apps/hwtest/lowlevel/lowlevel.cpp index 15fbaac5a..ff466c7cb 100644 --- a/apps/hwtest/lowlevel/lowlevel.cpp +++ b/apps/hwtest/lowlevel/lowlevel.cpp @@ -72,13 +72,21 @@ void CommandList::dispatch(const char * command) const { Ion::Console::writeLine("NOT_FOUND"); } - +static const char * sSyntaxError = "SYNTAX_ERROR"; void command_ping(const char * input) { + if (input != nullptr) { + Ion::Console::writeLine(sSyntaxError); + return; + } Ion::Console::writeLine("PONG"); } void command_mcu_serial(const char * input) { + if (input != nullptr) { + Ion::Console::writeLine(sSyntaxError); + return; + } char response[11+24+1] = {'M', 'C', 'U', '_', 'S', 'E', 'R', 'I', 'A', 'L', '=', 0}; strlcpy(response+11, Ion::serialNumber(), 25); Ion::Console::writeLine(response); @@ -105,7 +113,7 @@ static inline uint32_t hexNumber(const char * s) { void command_led(const char * input) { // Input must be of the form "0xAABBCC" if (input == nullptr || input[0] != '0' || input[1] != 'x' || !isHex(input[2]) ||!isHex(input[3]) || !isHex(input[4]) || !isHex(input[5]) || !isHex(input[6]) || !isHex(input[7]) || input[8] != NULL) { - Ion::Console::writeLine("SYNTAX_ERROR"); + Ion::Console::writeLine(sSyntaxError); return; } uint32_t hexColor = hexNumber(input+2); @@ -117,7 +125,7 @@ void command_led(const char * input) { void command_backlight(const char * input) { // Input must be of the form "0xAA" if (input == nullptr || input[0] != '0' || input[1] != 'x' || !isHex(input[2]) ||!isHex(input[3]) || input[4] != NULL) { - Ion::Console::writeLine("SYNTAX_ERROR"); + Ion::Console::writeLine(sSyntaxError); return; } uint32_t brightness = hexNumber(input+2); @@ -126,6 +134,10 @@ void command_backlight(const char * input) { } void command_adc(const char * input) { + if (input != nullptr) { + Ion::Console::writeLine(sSyntaxError); + return; + } float result = Ion::Battery::voltage(); constexpr int precision = 8; constexpr int bufferSize = Poincare::Complex::bufferSizeForFloatsWithPrecision(precision); @@ -134,12 +146,39 @@ void command_adc(const char * input) { Ion::Console::writeLine(responseBuffer); } +void command_charge(const char * input) { + if (input != nullptr) { + Ion::Console::writeLine(sSyntaxError); + return; + } + if (Ion::Battery::isCharging()) { + Ion::Console::writeLine("CHARGE=ON"); + } else { + Ion::Console::writeLine("CHARGE=OFF"); + } +} + +void command_keyboard(const char * input) { + if (input != nullptr) { + Ion::Console::writeLine(sSyntaxError); + return; + } + char result[9+Ion::Keyboard::NumberOfKeys+1] = { 'K', 'E', 'Y', 'B', 'O', 'A', 'R', 'D', '=' }; + for (uint8_t i=0; i Date: Mon, 6 Mar 2017 10:17:50 +0100 Subject: [PATCH 12/12] [ion/device] Fix building console.o Change-Id: I4d59900fccbb6f08946195a28ff9728ea3498288 --- ion/src/device/Makefile | 1 + ion/src/device/console.cpp | 17 ----------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/ion/src/device/Makefile b/ion/src/device/Makefile index 230131df6..2a3870052 100644 --- a/ion/src/device/Makefile +++ b/ion/src/device/Makefile @@ -26,6 +26,7 @@ objs += $(addprefix ion/src/device/, \ ifneq ($(DEBUG),1) ifneq ($(COMPILER),llvm) ion/src/device/led.o: SFLAGS+=-O3 +ion/src/device/console.o: SFLAGS+=-O3 ion/src/device/display.o: SFLAGS+=-O3 endif endif diff --git a/ion/src/device/console.cpp b/ion/src/device/console.cpp index febd68445..435b69231 100644 --- a/ion/src/device/console.cpp +++ b/ion/src/device/console.cpp @@ -30,23 +30,6 @@ void readLine(char * line, int maxLineLength) { cursor++; } } -/* - - lastChar - - char c = Device::recvChar(); - - char * lineEnd = line + maxLineLength; - - while (line < lineEnd) { - *line++ = Device::recvChar(); - if (*line == '\r') { - break; - } - } - *line = 0; -} -*/ } }