Commit 0e6386ee authored by Jake Read's avatar Jake Read

scratch

parents
# ATSAMD51 Documentation
`` !warn! violently incomplete ``
Herein lies some source code for the ATSAMD51, made arduino-compatible [by the folks at Adafruit](https://www.adafruit.com/product/3382).
\ No newline at end of file
/*
* pin.c
*
* Created: 2/5/2018 11:21:37 PM
* Author: Jake
*/
#include "pin.h"
#include "sam.h"
pin_t pin_new(PortGroup *port, uint32_t pin_number){
pin_t pin;
pin.port = port;
pin.pin = pin_number;
pin.bm = (uint32_t)(1 << pin_number);
return pin;
}
void pin_output(pin_t *pin){
pin->port->DIRSET.reg = pin->bm;
pin->port->OUTCLR.reg = pin->bm;
}
void pin_input(pin_t *pin){
pin->port->DIRCLR.reg = pin->bm;
pin->port->PINCFG[pin->pin].bit.INEN = 1;
}
void pin_pullup(pin_t *pin){
pin->port->PINCFG[pin->pin].bit.PULLEN = 1;
pin->port->OUTSET.reg |= pin->bm;
}
void pin_pulldown(pin_t *pin){
pin->port->PINCFG[pin->pin].bit.PULLEN = 1;
}
void pin_set(pin_t *pin){
pin->port->OUTSET.reg = pin->bm;
}
void pin_clear(pin_t *pin){
pin->port->OUTCLR.reg = pin->bm;
}
void pin_toggle(pin_t *pin){
pin->port->OUTTGL.reg = pin->bm;
}
int pin_read(pin_t *pin){
return pin->port->IN.reg & pin->bm;
}
\ No newline at end of file
/*
* pin.h
*
* Created: 2/5/2018 11:21:47 PM
* Author: Jake
*/
#ifndef PIN_H_
#define PIN_H_
#include "sam.h"
typedef struct {
PortGroup *port;
uint32_t pin;
uint32_t bm; // bitmask
} pin_t;
pin_t pin_new(PortGroup *port, uint32_t pin);
void pin_output(pin_t *pin);
void pin_input(pin_t *pin);
void pin_pullup(pin_t *pin);
void pin_pulldown(pin_t *pin);
void pin_set(pin_t *pin);
void pin_clear(pin_t *pin);
void pin_toggle(pin_t *pin);
int pin_read(pin_t *pin);
#endif /* PIN_H_ */
\ No newline at end of file
/*
* pwm.c
*
* Created: 2/17/2018 10:22:16 PM
* Author: Jake
*/
#include "pwm_foc.h"
#include "hardware.h"
void pwmsetup_foc(void){
/* TCC SETUP */
// from 49.6.2.1
// a few registers are protected - and can only be updated when
// TCCn.CTRLA.ENABLE = 0
// FCTRLA and FCTRLB, WEXCTRL, DRVCTRL, and EVCTRL
// (4) Configure Output Pin with PORT->Group[n].DIRSET.reg
// PA8 PA9 PA10 PA12, PB10 PB11
// 32.9.13
PORT->Group[0].DIRSET.reg |= (uint32_t)(1 << 8) | (uint32_t)(1 << 9) | (uint32_t)(1 << 10) | (uint32_t)(1 << 12);
PORT->Group[1].DIRSET.reg |= (uint32_t)(1 << 10) | (uint32_t)(1 << 11);
// 1 lo / hi
PORT->Group[0].PINCFG[10].bit.PMUXEN = 1;
PORT->Group[0].PMUX[10>>1].reg |= PORT_PMUX_PMUXE(0x5); // on peripheral F
PORT->Group[0].PINCFG[12].bit.PMUXEN = 1;
PORT->Group[0].PMUX[12>>1].reg |= PORT_PMUX_PMUXE(0x5);
// 2 lo / hi
PORT->Group[0].PINCFG[9].bit.PMUXEN = 1;
PORT->Group[0].PMUX[9>>1].reg |= PORT_PMUX_PMUXO(0x5); // on peripheral F
PORT->Group[1].PINCFG[11].bit.PMUXEN = 1;
PORT->Group[1].PMUX[11>>1].reg |= PORT_PMUX_PMUXO(0x5);
// 3 lo / hi
PORT->Group[0].PINCFG[8].bit.PMUXEN = 1;
PORT->Group[0].PMUX[8>>1].reg |= PORT_PMUX_PMUXE(0x5); // on peripheral F
PORT->Group[1].PINCFG[10].bit.PMUXEN = 1;
PORT->Group[1].PMUX[10>>1].reg |= PORT_PMUX_PMUXE(0x5);
// (1) enable the TCC Bus Clock - CLK_TCCn_APB
// https://www.eevblog.com/forum/microcontrollers/atmel-sam-d-tc-and-tcc-(no-asf)/
TCC0->CTRLA.bit.ENABLE = 0;
MCLK->APBBMASK.reg |= MCLK_APBBMASK_TCC0; // at 15.8.9
GCLK->GENCTRL[5].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) | GCLK_GENCTRL_GENEN;
while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL5);
GCLK->PCHCTRL[TCC0_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK5;
TCC0->CTRLA.reg |= TCC_CTRLA_PRESCALER_DIV4 | TCC_CTRLA_PRESCSYNC_PRESC |TCC_CTRLA_RESOLUTION(0);
// (2) Select Waveform Generation operation in the WAVE register WAVE.WAVEGEN
// we want dual slope pwm
TCC0->WAVE.reg = TCC_WAVE_WAVEGEN_DSBOTH; // 'dual slope both' - updates on both hi and lo of slope ?
// (3) We want OTMX - Output Matrix Channel Pin Routing Configuration - at 0x0
TCC0->WEXCTRL.reg = TCC_WEXCTRL_DTHS(1) | TCC_WEXCTRL_DTLS(1) |
TCC_WEXCTRL_DTIEN1 | TCC_WEXCTRL_DTIEN2 | TCC_WEXCTRL_DTIEN3 | TCC_WEXCTRL_DTIEN0 |
TCC_WEXCTRL_OTMX(0);
TCC0->PER.reg = TCC_PER_PER(256);
TCC0->COUNT.reg = 0;
TCC0->CCBUF[0].reg = 0; // '3'
TCC0->CCBUF[1].reg = 0; // '2'
TCC0->CCBUF[2].reg = 0; // '1'
TCC0->CCBUF[3].reg = 0;
// (4) Enable with CTRLA.ENABLE
TCC0->CTRLA.bit.ENABLE = 1;
while(TCC0->SYNCBUSY.bit.ENABLE);
}
#define PWMFOC_MIN_PWM 3
#define PWMFOC_MAX_PWM 253
void pwmupdate_foc(uint32_t one, uint32_t two, uint32_t three){
pwm_bounds(&three);
pwm_bounds(&two);
pwm_bounds(&one);
/*
uart_sendchar_buffered(&up1, one);
uart_sendchar_buffered(&up1, two);
uart_sendchar_buffered(&up1, three);
*/
TCC0->CCBUF[0].reg = three; // '3'
TCC0->CCBUF[1].reg = two; // '2'
TCC0->CCBUF[2].reg = one; // '1'
}
void pwm_bounds(uint32_t *val){
if(*val > PWMFOC_MAX_PWM){
*val = PWMFOC_MAX_PWM;
} else if(*val < PWMFOC_MIN_PWM){
*val = PWMFOC_MIN_PWM;
}
}
\ No newline at end of file
/*
* pwm_foc.h
*
* Created: 2/17/2018 10:22:37 PM
* Author: Jake
*/
#ifndef PWM_FOC_H_
#define PWM_FOC_H_
#include "sam.h"
void pwmsetup_foc(void);
// 0 -> 255 (but count deadtime?) midpoint is 126
void pwmupdate_foc(uint32_t one, uint32_t two, uint32_t three);
// asserts min and max for pwm
void pwm_bounds(uint32_t *val);
#endif /* PWM_FOC_H_ */
\ No newline at end of file
/*
* spiport.c
*
* Created: 2/7/2018 10:51:42 AM
* Author: Jake
*/
#include "spiport.h"
spiport_t spi_new(Sercom *com, PortGroup *port, uint32_t miso_pin, uint32_t mosi_pin, uint32_t sck_pin, uint32_t csn_pin, uint32_t apbx, uint32_t peripheral){
spiport_t spi;
spi.com = com;
spi.port = port;
spi.miso_pin = miso_pin;
spi.miso_bm = (uint32_t)(1 << miso_pin);
spi.mosi_pin = mosi_pin;
spi.mosi_bm = (uint32_t)(1 << mosi_pin);
spi.sck_pin = sck_pin;
spi.sck_bm = (uint32_t)(1 << sck_pin);
spi.csn_pin = csn_pin;
spi.csn_bm = (uint32_t)(1 << csn_pin);
spi.apbx = apbx;
spi.peripheral = peripheral;
return spi;
}
void spi_init(spiport_t *spi, uint32_t gclknum, uint32_t gclkidcore, uint8_t baud, uint8_t dipo, uint8_t dopo, uint8_t csnhardware, uint8_t cpha, uint8_t cpol, uint8_t lsbfirst){
// to add to this lib: doc, cleaning, options properly enumerated: do when doing AS5147
// clk is unmasked (external to this lib)
// do pin configs
spi->port->DIRCLR.reg = spi->miso_bm;
spi->port->PINCFG[spi->miso_pin].bit.PMUXEN = 1;
spi->port->DIRSET.reg = spi->mosi_bm | spi->sck_bm | spi->csn_bm;
spi->port->PINCFG[spi->mosi_pin].bit.PMUXEN = 1;
spi->port->PINCFG[spi->sck_pin].bit.PMUXEN = 1;
if(csnhardware){
spi->port->PINCFG[spi->csn_pin].bit.PMUXEN = 1;
spi->com->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_MSSEN;
if(spi->csn_pin % 2){ // yes if odd
spi->port->PMUX[spi->csn_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
} else {
spi->port->PMUX[spi->csn_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
}
}else{
spi->port->OUTSET.reg = spi->csn_bm; // set hi to start! - this should properly depend on our CPHA !
}
if(spi->miso_pin % 2){ // yes if odd
spi->port->PMUX[spi->miso_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
} else {
spi->port->PMUX[spi->miso_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
}
if(spi->mosi_pin % 2){ // yes if odd
spi->port->PMUX[spi->mosi_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
} else {
spi->port->PMUX[spi->mosi_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
}
if(spi->sck_pin % 2){ // yes if odd
spi->port->PMUX[spi->sck_pin >> 1].reg |= PORT_PMUX_PMUXO(spi->peripheral);
} else {
spi->port->PMUX[spi->sck_pin >> 1].reg |= PORT_PMUX_PMUXE(spi->peripheral);
}
// build a clock for
GCLK->GENCTRL[gclknum].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) | GCLK_GENCTRL_GENEN;
while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclknum));
GCLK->PCHCTRL[gclkidcore].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(gclknum);
// now some SERCOM
// tmc spi is clock inactive hi
// tmc spi latches data on the rising edge of sck and drives data out on the next falling edge
spi->com->SPI.CTRLA.bit.ENABLE = 0;
// master, data in pinout, data out pinout
spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x03);
if(cpol){
spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_CPOL;
}
if(cpha){
spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_CPHA;
}
if(lsbfirst){
SERCOM0->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_DORD; // 0 MSB, 1 LSB
}
spi->com->SPI.CTRLA.reg |= SERCOM_SPI_CTRLA_DIPO(dipo) | SERCOM_SPI_CTRLA_DOPO(dopo);
// these to defaults, but here for show
//SERCOM0->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_CHSIZE(0x0); // 8 bits character - 0x0, so no need to set
// BAUD
// f_baud = f_ref / (2 * (BAUD +1)) so BAUD = f_ref / (2 * f_baud) - 1
spi->com->SPI.BAUD.reg |= SERCOM_SPI_BAUD_BAUD(baud);
// use hardware slave select, enable receiver
spi->com->SPI.CTRLB.reg |= SERCOM_SPI_CTRLB_RXEN; //SERCOM_SPI_CTRLB_MSSEN |
// 8 or 32 bits
// do if(bits)
//spi->com->SPI.CTRLC.reg |= SERCOM_SPI_CTRLC_DATA32B;
//spi->com->SPI.LENGTH.reg |= SERCOM_SPI_LENGTH_LENEN | SERCOM_SPI_LENGTH_LEN(20);
// turnt it up
spi->com->SPI.CTRLA.bit.ENABLE = 1;
}
void spi_txchar_polled(spiport_t *spi, uint8_t data){
while(!(spi->com->SPI.INTFLAG.bit.DRE));
spi->com->SPI.DATA.reg = SERCOM_SPI_DATA_DATA(data);
}
void spi_txchars_polled(spiport_t *spi, uint8_t *data, uint8_t length){
spi->port->OUTCLR.reg = spi->csn_bm;
for(int i = 0; i < length; i ++){
spi_txchar_polled(spi, data[i]);
}
while(!spi->com->SPI.INTFLAG.bit.TXC); // wait for complete of last byte before
spi->port->OUTSET.reg = spi->csn_bm;
}
void spi_txrxchars_polled(spiport_t *spi, uint8_t *data_tx, uint8_t length, uint8_t *data_rx){
spi->port->OUTCLR.reg = spi->csn_bm;
for(int i = 0; i < length; i ++){
while(!(spi->com->SPI.INTFLAG.bit.DRE));
spi->com->SPI.DATA.reg = SERCOM_SPI_DATA_DATA(data_tx[i]);
while(!(spi->com->SPI.INTFLAG.bit.RXC)); // wait for data to come out of rx buffer
data_rx[i] = spi->com->SPI.DATA.reg;
}
while(!spi->com->SPI.INTFLAG.bit.TXC); // wait for complete of last byte before
spi->port->OUTSET.reg = spi->csn_bm;
}
void spi_txrxchar_polled(spiport_t *spi, uint8_t data, uint8_t *rxdata){
// not yet bc so far have not needed single receive
}
\ No newline at end of file
/*
* spiport.h
*
* Created: 2/7/2018 10:51:52 AM
* Author: Jake
*/
#ifndef SPIPORT_H_
#define SPIPORT_H_
#include "sam.h"
// TODO: cleaning settings / init values for prettiness, ease of use on variable devices
typedef struct{
Sercom *com;
PortGroup *port;
uint32_t miso_pin;
uint32_t miso_bm;
uint32_t mosi_pin;
uint32_t mosi_bm;
uint32_t sck_pin;
uint32_t sck_bm;
uint32_t csn_pin;
uint32_t csn_bm;
uint32_t apbx;
uint32_t peripheral;
uint32_t baud;
}spiport_t;
spiport_t spi_new(Sercom *com, PortGroup *port, uint32_t miso_pin, uint32_t mosi_pin, uint32_t sck_pin, uint32_t csn_pin, uint32_t apbx, uint32_t peripheral);
void spi_init(spiport_t *spi, uint32_t gclknum, uint32_t gclkidcore, uint8_t baud, uint8_t dipo, uint8_t dopo, uint8_t csnhardware, uint8_t cpha, uint8_t cpol, uint8_t lsbfirst); // bits: 0: 8, 1: 32
void spi_txchar_polled(spiport_t *spi, uint8_t data);
void spi_txchars_polled(spiport_t *spi, uint8_t *data, uint8_t length);
void spi_txrxchar_polled(spiport_t *spi, uint8_t data, uint8_t *rxdata); // not implemented, use
void spi_txrxchars_polled(spiport_t *spi, uint8_t *data_tx, uint8_t length, uint8_t *data_rx);
#endif /* SPIPORT_H_ */
\ No newline at end of file
/*
* uartport.c
*
* Created: 2/6/2018 10:48:26 AM
* Author: Jake
*/
#include "uartport.h"
uartport_t uart_new(Sercom *com, PortGroup *port, ringbuffer_t *rbrx, ringbuffer_t *rbtx, uint32_t rx_pin, uint32_t tx_pin, uint32_t apbx, uint32_t peripheral){
uartport_t uart;
uart.com = com;
uart.port = port;
uart.rbrx = rbrx;
uart.rbtx = rbtx;
uart.rx_pin = rx_pin;
uart.rx_bm = (uint32_t)(1 << rx_pin);
uart.tx_pin = tx_pin;
uart.tx_bm = (uint32_t)(1 << tx_pin);
uart.apbx = apbx;
uart.peripheral = peripheral;
// add ringbuffers
return uart;
}
void uart_init(uartport_t *uart, uint32_t gclknum, uint32_t gclkidcore, uint16_t baud){
// rx pin setups
uart->port->DIRCLR.reg = uart->rx_bm;
uart->port->PINCFG[uart->rx_pin].bit.PMUXEN = 1;
if(uart->rx_pin % 2){ // yes if odd
uart->port->PMUX[uart->rx_pin >> 1].reg |= PORT_PMUX_PMUXO(uart->peripheral);
} else {
uart->port->PMUX[uart->rx_pin >> 1].reg |= PORT_PMUX_PMUXE(uart->peripheral);
}
// tx pin setups
uart->port->DIRSET.reg = uart->tx_bm;
uart->port->PINCFG[uart->tx_pin].bit.PMUXEN = 1;
if(uart->tx_pin % 2){ // yes if odd
uart->port->PMUX[uart->tx_pin >> 1].reg |= PORT_PMUX_PMUXO(uart->peripheral);
} else {
uart->port->PMUX[uart->tx_pin >> 1].reg |= PORT_PMUX_PMUXE(uart->peripheral);
}
// unmask the clock
// -> have to do this manually b/c unfavourable api
GCLK->GENCTRL[gclknum].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_DFLL) | GCLK_GENCTRL_GENEN;
while(GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclknum));
GCLK->PCHCTRL[gclkidcore].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(gclknum);
// now the sercom
while(uart->com->USART.SYNCBUSY.bit.ENABLE);
uart->com->USART.CTRLA.bit.ENABLE = 0;
while(uart->com->USART.SYNCBUSY.bit.SWRST);
uart->com->USART.CTRLA.bit.SWRST = 1;
while(uart->com->USART.SYNCBUSY.bit.SWRST);
while(uart->com->USART.SYNCBUSY.bit.SWRST || SERCOM5->USART.SYNCBUSY.bit.ENABLE);
uart->com->USART.CTRLA.reg = SERCOM_USART_CTRLA_MODE(1) | SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(0);
while(uart->com->USART.SYNCBUSY.bit.CTRLB);
uart->com->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0);
/*
BAUD = 65536*(1-S*(fBAUD/fref))
where S is samples per bit, 16 for async uart
where fBAUD is the rate that you want
where fref is the peripheral clock from GCLK, in this case (and most) 48MHz
*/
uart->com->USART.BAUD.reg = baud;
while(uart->com->USART.SYNCBUSY.bit.ENABLE);
uart->com->USART.CTRLA.bit.ENABLE = 1;
uart->com->USART.INTENSET.bit.RXC = 1; // set receive interrupt on, see 34.6.4.2
}
void uart_sendchar_polled(uartport_t *uart, uint8_t data){
while(!uart->com->USART.INTFLAG.bit.DRE);
uart->com->USART.DATA.reg = data;
}
void uart_sendchar_buffered(uartport_t *uart, uint8_t data){
rb_putchar(uart->rbtx, data); // dump it in there
uart->com->USART.INTENSET.bit.DRE = 1; // set up the volley
}
void uart_rxhandler(uartport_t *uart){
uint8_t data = uart->com->USART.DATA.reg;
rb_putchar(uart->rbrx, data);
}
void uart_txhandler(uartport_t *uart){
if(!rb_empty(uart->rbtx)){
uart->com->USART.DATA.reg = rb_get(uart->rbtx);
} else {
uart->com->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE;
}
}
\ No newline at end of file
/*
* uartport.h
*
* Created: 2/6/2018 10:47:56 AM
* Author: Jake
*/
#ifndef UARTPORT_H_
#define UARTPORT_H_
#include "sam.h"
#include "ringbuffer.h"
#define HARDWARE_IS_APBA 0
#define HARDWARE_IS_APBB 1
#define HARDWARE_IS_APBC 2
#define HARDWARE_IS_APBD 3
#define HARDWARE_ON_PERIPHERAL_A 0x0
#define HARDWARE_ON_PERIPHERAL_B 0x1
#define HARDWARE_ON_PERIPHERAL_C 0x2
#define HARDWARE_ON_PERIPHERAL_D 0x3
typedef struct{
Sercom *com;
PortGroup *port;
ringbuffer_t *rbrx;
ringbuffer_t *rbtx;
uint32_t rx_pin;
uint32_t rx_bm;
uint32_t tx_pin;
uint32_t tx_bm;
uint32_t apbx;
uint32_t peripheral;
uint16_t baud;
}uartport_t;
uartport_t uart_new(Sercom *com, PortGroup *port, ringbuffer_t *rbrx, ringbuffer_t *rbtx, uint32_t rx_pin, uint32_t tx_pin, uint32_t apbx, uint32_t peripheral);
void uart_init(uartport_t *uart, uint32_t gclknum, uint32_t gclkidcore, uint16_t baud);
void uart_sendchar_polled(uartport_t *uart, uint8_t data);
void uart_sendchar_buffered(uartport_t *uart, uint8_t data);
void uart_rxhandler(uartport_t *uart);
void uart_txhandler(uartport_t *uart);
#endif /* UARTPORT_H_ */
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment