commit
c51067f197
|
|
@ -125,7 +125,7 @@ endif()
|
||||||
|
|
||||||
if(CMAKE_CROSSCOMPILING)
|
if(CMAKE_CROSSCOMPILING)
|
||||||
# mcu related settings
|
# mcu related settings
|
||||||
set(MCU_FLAGS -mmcu=atmega32u4)
|
set(MCU_FLAGS -mmcu=atmega32u4 -DF_CPU=16000000L)
|
||||||
add_compile_options(${MCU_FLAGS})
|
add_compile_options(${MCU_FLAGS})
|
||||||
add_link_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-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
|
# generate linker map file
|
||||||
target_link_options(firmware PUBLIC -Wl,-Map=firmware.map)
|
target_link_options(firmware PUBLIC -Wl,-Map=firmware.map)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
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.
|
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
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
#pragma once
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
|
@ -30,9 +31,6 @@ namespace gpio {
|
||||||
Mode mode;
|
Mode mode;
|
||||||
Pull pull;
|
Pull pull;
|
||||||
Level level;
|
Level level;
|
||||||
inline GPIO_InitTypeDef()
|
|
||||||
: mode(Mode::input)
|
|
||||||
, pull(Pull::none) {};
|
|
||||||
inline GPIO_InitTypeDef(Mode mode, Pull pull)
|
inline GPIO_InitTypeDef(Mode mode, Pull pull)
|
||||||
: mode(mode)
|
: mode(mode)
|
||||||
, pull(pull) {};
|
, pull(pull) {};
|
||||||
|
|
@ -41,36 +39,50 @@ namespace gpio {
|
||||||
, level(level) {};
|
, 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)
|
if (level == Level::high)
|
||||||
port->PORTx |= (1 << pin);
|
portPin.port->PORTx |= (1 << portPin.pin);
|
||||||
else
|
else
|
||||||
port->PORTx &= ~(1 << pin);
|
portPin.port->PORTx &= ~(1 << portPin.pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Level ReadPin(GPIO_TypeDef *const port, const uint8_t pin) {
|
__attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) {
|
||||||
return (Level)(port->PINx & (1 << pin));
|
return (Level)(portPin.port->PINx & (1 << portPin.pin));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void TogglePin(GPIO_TypeDef *const port, const uint8_t pin) {
|
__attribute__((always_inline)) inline void TogglePin(const GPIO_pin portPin) {
|
||||||
port->PINx |= (1 << pin);
|
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) {
|
if (GPIO_Init.mode == Mode::output) {
|
||||||
WritePin(port, pin, GPIO_Init.level);
|
WritePin(portPin, GPIO_Init.level);
|
||||||
port->DDRx |= (1 << pin);
|
portPin.port->DDRx |= (1 << portPin.pin);
|
||||||
} else {
|
} else {
|
||||||
port->DDRx &= ~(1 << pin);
|
portPin.port->DDRx &= ~(1 << portPin.pin);
|
||||||
WritePin(port, pin, (Level)GPIO_Init.pull);
|
WritePin(portPin, (Level)GPIO_Init.pull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define GPIOA ((hal::gpio::GPIO_TypeDef *)&PINA)
|
||||||
#define GPIOB ((hal::gpio::GPIO_TypeDef *)&PINB)
|
#define GPIOB ((hal::gpio::GPIO_TypeDef *)&PINB)
|
||||||
#define GPIOC ((hal::gpio::GPIO_TypeDef *)&PINC)
|
#define GPIOC ((hal::gpio::GPIO_TypeDef *)&PINC)
|
||||||
#define GPIOD ((hal::gpio::GPIO_TypeDef *)&PIND)
|
#define GPIOD ((hal::gpio::GPIO_TypeDef *)&PIND)
|
||||||
#define GPIOE ((hal::gpio::GPIO_TypeDef *)&PINE)
|
#define GPIOE ((hal::gpio::GPIO_TypeDef *)&PINE)
|
||||||
#define GPIOF ((hal::gpio::GPIO_TypeDef *)&PINF)
|
#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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
#pragma once
|
||||||
|
#include <inttypes.h>
|
||||||
|
#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)
|
||||||
47
src/main.cpp
47
src/main.cpp
|
|
@ -1,12 +1,42 @@
|
||||||
#include "logic/mm_control.h"
|
#include "logic/mm_control.h"
|
||||||
#include "hal/gpio.h"
|
#include "hal/gpio.h"
|
||||||
|
#include "hal/spi.h"
|
||||||
|
#include "pins.h"
|
||||||
|
|
||||||
/// One-time setup of HW and SW components
|
/// One-time setup of HW and SW components
|
||||||
/// Called before entering the loop() function
|
/// Called before entering the loop() function
|
||||||
void setup(){
|
void setup() {
|
||||||
using namespace hal::gpio;
|
using namespace hal;
|
||||||
hal::gpio::Init(GPIOB, 1, GPIO_InitTypeDef(Mode::output, Level::low));
|
|
||||||
|
|
||||||
|
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
|
/// Main loop of the firmware
|
||||||
|
|
@ -23,17 +53,16 @@ void setup(){
|
||||||
/// StepWhateverElseNeedsStepping();
|
/// StepWhateverElseNeedsStepping();
|
||||||
/// The idea behind the Step* routines is to keep each automaton non-blocking allowing for some “concurrency”.
|
/// 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.)
|
/// Some FW components will leverage ISR to do their stuff (UART, motor stepping?, etc.)
|
||||||
void loop(){
|
void loop() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
setup();
|
setup();
|
||||||
for(;;){
|
for (;;) {
|
||||||
using namespace hal::gpio;
|
using namespace hal::gpio;
|
||||||
WritePin(GPIOB, 5, Level::low);
|
WritePin(GPIO_pin(GPIOB, 5), Level::low);
|
||||||
TogglePin(GPIOB, 6);
|
TogglePin(GPIO_pin(GPIOB, 6));
|
||||||
if (hal::gpio::ReadPin(GPIOB, 7) == hal::gpio::Level::low)
|
if (hal::gpio::ReadPin(GPIO_pin(GPIOB, 7)) == hal::gpio::Level::low)
|
||||||
break;
|
break;
|
||||||
loop();
|
loop();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue