diff --git a/CMakeLists.txt b/CMakeLists.txt index ee55d68..63758b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,7 @@ endif() if(CMAKE_CROSSCOMPILING) # mcu related settings - set(MCU_FLAGS -mmcu=atmega32u4) + set(MCU_FLAGS -mmcu=atmega32u4 -DF_CPU=16000000L) add_compile_options(${MCU_FLAGS}) add_link_options(${MCU_FLAGS}) @@ -170,6 +170,8 @@ objcopy(firmware "ihex" ".hex") add_custom_command(TARGET firmware POST_BUILD COMMAND avr-objdump ARGS -CSd firmware > firmware.txt) +add_custom_command(TARGET firmware POST_BUILD COMMAND avr-size ARGS -C --mcu=atmega32u4 firmware) + # generate linker map file target_link_options(firmware PUBLIC -Wl,-Map=firmware.map) diff --git a/src/hal/_rules.txt b/src/hal/_rules.txt index 65c89c5..9dae508 100644 --- a/src/hal/_rules.txt +++ b/src/hal/_rules.txt @@ -2,3 +2,6 @@ Use a class whenever you need to store some context data along with the function A typical scenario is the UART which uses some RX and TX buffers. Use a simple C-style otherwise, but it is advised to wrap the interface into a namespace as proposed in existing header files. + +`__attribute__((always_inline)) inline` was necessary for most functions because the generated code wasn't efficient enough otherwise. +It will be interesting when the STM32 hal will have to be included as well. Hopefully it won't be a nightmare :P diff --git a/src/hal/gpio.h b/src/hal/gpio.h index 80f3545..4d473bf 100644 --- a/src/hal/gpio.h +++ b/src/hal/gpio.h @@ -1,3 +1,4 @@ +#pragma once #include #include @@ -30,9 +31,6 @@ namespace gpio { Mode mode; Pull pull; Level level; - inline GPIO_InitTypeDef() - : mode(Mode::input) - , pull(Pull::none) {}; inline GPIO_InitTypeDef(Mode mode, Pull pull) : mode(mode) , pull(pull) {}; @@ -41,36 +39,50 @@ namespace gpio { , level(level) {}; }; - inline void WritePin(GPIO_TypeDef *const port, const uint8_t pin, Level level) { + struct GPIO_pin { + GPIO_TypeDef *const port; + const uint8_t pin; + inline GPIO_pin(GPIO_TypeDef *const port, const uint8_t pin) + : port(port) + , pin(pin) {}; + }; + + __attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) { if (level == Level::high) - port->PORTx |= (1 << pin); + portPin.port->PORTx |= (1 << portPin.pin); else - port->PORTx &= ~(1 << pin); + portPin.port->PORTx &= ~(1 << portPin.pin); } - inline Level ReadPin(GPIO_TypeDef *const port, const uint8_t pin) { - return (Level)(port->PINx & (1 << pin)); + __attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) { + return (Level)(portPin.port->PINx & (1 << portPin.pin)); } - inline void TogglePin(GPIO_TypeDef *const port, const uint8_t pin) { - port->PINx |= (1 << pin); + __attribute__((always_inline)) inline void TogglePin(const GPIO_pin portPin) { + portPin.port->PINx |= (1 << portPin.pin); } - inline void Init(GPIO_TypeDef *const port, const uint8_t pin, GPIO_InitTypeDef GPIO_Init) { + __attribute__((always_inline)) inline void Init(const GPIO_pin portPin, GPIO_InitTypeDef GPIO_Init) { if (GPIO_Init.mode == Mode::output) { - WritePin(port, pin, GPIO_Init.level); - port->DDRx |= (1 << pin); + WritePin(portPin, GPIO_Init.level); + portPin.port->DDRx |= (1 << portPin.pin); } else { - port->DDRx &= ~(1 << pin); - WritePin(port, pin, (Level)GPIO_Init.pull); + portPin.port->DDRx &= ~(1 << portPin.pin); + WritePin(portPin, (Level)GPIO_Init.pull); } } } } +#define GPIOA ((hal::gpio::GPIO_TypeDef *)&PINA) #define GPIOB ((hal::gpio::GPIO_TypeDef *)&PINB) #define GPIOC ((hal::gpio::GPIO_TypeDef *)&PINC) #define GPIOD ((hal::gpio::GPIO_TypeDef *)&PIND) #define GPIOE ((hal::gpio::GPIO_TypeDef *)&PINE) #define GPIOF ((hal::gpio::GPIO_TypeDef *)&PINF) +#define GPIOG ((hal::gpio::GPIO_TypeDef *)&PING) +#define GPIOH ((hal::gpio::GPIO_TypeDef *)&PINH) +#define GPIOJ ((hal::gpio::GPIO_TypeDef *)&PINJ) +#define GPIOK ((hal::gpio::GPIO_TypeDef *)&PINK) +#define GPIOL ((hal::gpio::GPIO_TypeDef *)&PINL) diff --git a/src/hal/pins.h b/src/hal/pins.h deleted file mode 100644 index 8745ad5..0000000 --- a/src/hal/pins.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -/// Hardware Abstraction Layer for the CPU's features and peripherals - -namespace hal { -namespace pins { - - /// pin definitions - -} // namespace pins -} // namespace hal diff --git a/src/hal/spi.h b/src/hal/spi.h new file mode 100644 index 0000000..5e067d3 --- /dev/null +++ b/src/hal/spi.h @@ -0,0 +1,48 @@ +#pragma once +#include +#include "gpio.h" + +/// SPI interface + +namespace hal { +namespace spi { + struct SPI_TypeDef { + volatile uint8_t SPCRx; + volatile uint8_t SPSRx; + volatile uint8_t SPDRx; + }; + + struct SPI_InitTypeDef { + hal::gpio::GPIO_pin miso_pin; + hal::gpio::GPIO_pin mosi_pin; + hal::gpio::GPIO_pin sck_pin; + hal::gpio::GPIO_pin ss_pin; + uint8_t prescaler; + uint8_t cpha; + uint8_t cpol; + }; + + __attribute__((always_inline)) inline void Init(SPI_TypeDef *const hspi, SPI_InitTypeDef *const conf) { + using namespace hal; + gpio::Init(conf->miso_pin, gpio::GPIO_InitTypeDef(gpio::Mode::input, gpio::Pull::none)); + gpio::Init(conf->mosi_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); + gpio::Init(conf->sck_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); + gpio::Init(conf->ss_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::high)); //the AVR requires this pin to be an output for SPI master mode to work properly. + + const uint8_t spi2x = (conf->prescaler == 7) ? 0 : (conf->prescaler & 0x01); + const uint8_t spr = ((conf->prescaler - 1) >> 1) & 0x03; + + hspi->SPCRx = (0 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | ((conf->cpol & 0x01) << CPOL) | ((conf->cpha & 0x01) << CPHA) | (spr << SPR0); + hspi->SPSRx = (spi2x << SPI2X); + } + + __attribute__((always_inline)) inline uint8_t TxRx(SPI_TypeDef *const hspi, uint8_t val) { + hspi->SPDRx = val; + while (!(hspi->SPSRx & (1 << SPIF))) + ; + return hspi->SPDRx; + } +} +} + +#define SPI0 ((hal::spi::SPI_TypeDef *)&SPCR) diff --git a/src/main.cpp b/src/main.cpp index f26c6b1..679406f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,42 @@ #include "logic/mm_control.h" #include "hal/gpio.h" +#include "hal/spi.h" +#include "pins.h" /// One-time setup of HW and SW components /// Called before entering the loop() function -void setup(){ - using namespace hal::gpio; - hal::gpio::Init(GPIOB, 1, GPIO_InitTypeDef(Mode::output, Level::low)); +void setup() { + using namespace hal; + spi::SPI_InitTypeDef spi_conf = { + .miso_pin = gpio::GPIO_pin(TMC2130_SPI_MISO_PIN), + .mosi_pin = gpio::GPIO_pin(TMC2130_SPI_MOSI_PIN), + .sck_pin = gpio::GPIO_pin(TMC2130_SPI_SCK_PIN), + .ss_pin = gpio::GPIO_pin(TMC2130_SPI_SS_PIN), + .prescaler = 2, //4mhz + .cpha = 1, + .cpol = 1, + }; + spi::Init(SPI0, &spi_conf); + + // SPI example + gpio::Init(gpio::GPIO_pin(GPIOC, 6), gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::high)); + uint8_t dat[5]; + gpio::WritePin(gpio::GPIO_pin(GPIOC, 6), gpio::Level::low); + spi::TxRx(SPI0, 0x01); + spi::TxRx(SPI0, 0x00); + spi::TxRx(SPI0, 0x00); + spi::TxRx(SPI0, 0x00); + spi::TxRx(SPI0, 0x00); + gpio::WritePin(gpio::GPIO_pin(GPIOC, 6), gpio::Level::high); + gpio::WritePin(gpio::GPIO_pin(GPIOC, 6), gpio::Level::low); + dat[0] = spi::TxRx(SPI0, 0x00); + dat[1] = spi::TxRx(SPI0, 0x00); + dat[2] = spi::TxRx(SPI0, 0x00); + dat[3] = spi::TxRx(SPI0, 0x00); + dat[4] = spi::TxRx(SPI0, 0x00); + gpio::WritePin(gpio::GPIO_pin(GPIOC, 6), gpio::Level::high); + (void)dat; } /// Main loop of the firmware @@ -23,17 +53,16 @@ void setup(){ /// StepWhateverElseNeedsStepping(); /// The idea behind the Step* routines is to keep each automaton non-blocking allowing for some “concurrency”. /// Some FW components will leverage ISR to do their stuff (UART, motor stepping?, etc.) -void loop(){ - +void loop() { } int main() { setup(); - for(;;){ + for (;;) { using namespace hal::gpio; - WritePin(GPIOB, 5, Level::low); - TogglePin(GPIOB, 6); - if (hal::gpio::ReadPin(GPIOB, 7) == hal::gpio::Level::low) + WritePin(GPIO_pin(GPIOB, 5), Level::low); + TogglePin(GPIO_pin(GPIOB, 6)); + if (hal::gpio::ReadPin(GPIO_pin(GPIOB, 7)) == hal::gpio::Level::low) break; loop(); } diff --git a/src/pins.h b/src/pins.h new file mode 100644 index 0000000..154436f --- /dev/null +++ b/src/pins.h @@ -0,0 +1,9 @@ +#pragma once +#include "hal/gpio.h" + +/// pin definitions + +#define TMC2130_SPI_MISO_PIN GPIOB, 3 +#define TMC2130_SPI_MOSI_PIN GPIOB, 2 +#define TMC2130_SPI_SCK_PIN GPIOB, 1 +#define TMC2130_SPI_SS_PIN GPIOB, 0