sam3: Rename src/sam3x8e to src/sam3
This is in preparation for merging sam3 and sam4 code into one directory. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
29
src/sam3/Kconfig
Normal file
29
src/sam3/Kconfig
Normal file
@@ -0,0 +1,29 @@
|
||||
# Kconfig settings for SAM3 processors
|
||||
|
||||
if MACH_SAM3X8E
|
||||
|
||||
config SAM_SELECT
|
||||
bool
|
||||
default y
|
||||
select HAVE_GPIO
|
||||
select HAVE_GPIO_ADC
|
||||
select HAVE_GPIO_SPI
|
||||
select HAVE_GPIO_BITBANGING
|
||||
|
||||
config BOARD_DIRECTORY
|
||||
string
|
||||
default "sam3"
|
||||
|
||||
config CLOCK_FREQ
|
||||
int
|
||||
default 42000000 # 84000000/2
|
||||
|
||||
config SERIAL
|
||||
bool
|
||||
default y
|
||||
config SERIAL_BAUD
|
||||
depends on SERIAL
|
||||
int "Baud rate for serial port"
|
||||
default 250000
|
||||
|
||||
endif
|
||||
42
src/sam3/Makefile
Normal file
42
src/sam3/Makefile
Normal file
@@ -0,0 +1,42 @@
|
||||
# Additional SAM3 build rules
|
||||
|
||||
# Setup the toolchain
|
||||
CROSS_PREFIX=arm-none-eabi-
|
||||
|
||||
dirs-y += src/sam3 src/generic
|
||||
dirs-y += lib/sam3x/gcc/gcc
|
||||
|
||||
CFLAGS += -mthumb -mcpu=cortex-m3 -falign-loops=16
|
||||
CFLAGS += -Ilib/sam3x/include -Ilib/cmsis-core
|
||||
CFLAGS += -D__SAM3X8E__
|
||||
|
||||
CFLAGS_klipper.elf += -Llib/sam3x/gcc/gcc
|
||||
CFLAGS_klipper.elf += -T lib/sam3x/gcc/gcc/sam3x8e_flash.ld
|
||||
CFLAGS_klipper.elf += --specs=nano.specs --specs=nosys.specs
|
||||
|
||||
# Add source files
|
||||
src-y += sam3/main.c sam3/timer.c
|
||||
src-y += sam3/gpio.c sam3/adc.c sam3/spi.c
|
||||
src-y += generic/crc16_ccitt.c generic/alloc.c
|
||||
src-y += generic/armcm_irq.c generic/timer_irq.c
|
||||
src-y += ../lib/sam3x/gcc/system_sam3xa.c
|
||||
src-y += ../lib/sam3x/gcc/gcc/startup_sam3xa.c
|
||||
src-$(CONFIG_SERIAL) += sam3/serial.c generic/serial_irq.c
|
||||
|
||||
# Build the additional hex output file
|
||||
target-y += $(OUT)klipper.bin
|
||||
|
||||
$(OUT)klipper.bin: $(OUT)klipper.elf
|
||||
@echo " Creating hex file $@"
|
||||
$(Q)$(OBJCOPY) -O binary $< $@
|
||||
|
||||
# Flash rules
|
||||
lib/bossac/bin/bossac:
|
||||
@echo " Building bossac"
|
||||
$(Q)make -C lib/bossac bin/bossac
|
||||
|
||||
flash: $(OUT)klipper.bin lib/bossac/bin/bossac
|
||||
@echo " Flashing $^ to $(FLASH_DEVICE) via bossac"
|
||||
$(Q)if [ -z $(FLASH_DEVICE) ]; then echo "Please specify FLASH_DEVICE"; exit 1; fi
|
||||
$(Q)lib/bossac/bin/bossac -U -p "$(FLASH_DEVICE)" -a -e -w $(OUT)klipper.bin -v -b
|
||||
$(Q)lib/bossac/bin/bossac -p "$(FLASH_DEVICE)" -R > /dev/null 2>&1 || true
|
||||
90
src/sam3/adc.c
Normal file
90
src/sam3/adc.c
Normal file
@@ -0,0 +1,90 @@
|
||||
// Analog to digital support
|
||||
//
|
||||
// Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "autoconf.h" // CONFIG_CLOCK_FREQ
|
||||
#include "board/irq.h" // irq_save
|
||||
#include "command.h" // shutdown
|
||||
#include "compiler.h" // ARRAY_SIZE
|
||||
#include "gpio.h" // gpio_adc_setup
|
||||
#include "internal.h" // GPIO
|
||||
#include "sam3x8e.h" // ADC
|
||||
#include "sched.h" // sched_shutdown
|
||||
|
||||
static const uint8_t adc_pins[] = {
|
||||
GPIO('A', 2), GPIO('A', 3), GPIO('A', 4), GPIO('A', 6),
|
||||
GPIO('A', 22), GPIO('A', 23), GPIO('A', 24), GPIO('A', 16),
|
||||
GPIO('B', 12), GPIO('B', 13), GPIO('B', 17), GPIO('B', 18),
|
||||
GPIO('B', 19), GPIO('B', 20)
|
||||
};
|
||||
|
||||
#define ADC_FREQ_MAX 20000000
|
||||
DECL_CONSTANT(ADC_MAX, 4095);
|
||||
|
||||
struct gpio_adc
|
||||
gpio_adc_setup(uint8_t pin)
|
||||
{
|
||||
// Find pin in adc_pins table
|
||||
int chan;
|
||||
for (chan=0; ; chan++) {
|
||||
if (chan >= ARRAY_SIZE(adc_pins))
|
||||
shutdown("Not a valid ADC pin");
|
||||
if (adc_pins[chan] == pin)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(PMC->PMC_PCSR1 & (1 << (ID_ADC-32)))) {
|
||||
// Setup ADC
|
||||
PMC->PMC_PCER1 = 1 << (ID_ADC-32);
|
||||
uint32_t prescal = SystemCoreClock / (2 * ADC_FREQ_MAX) - 1;
|
||||
ADC->ADC_MR = (ADC_MR_PRESCAL(prescal)
|
||||
| ADC_MR_STARTUP_SUT768
|
||||
| ADC_MR_TRANSFER(1));
|
||||
}
|
||||
return (struct gpio_adc){ .bit = 1 << chan };
|
||||
}
|
||||
|
||||
// Try to sample a value. Returns zero if sample ready, otherwise
|
||||
// returns the number of clock ticks the caller should wait before
|
||||
// retrying this function.
|
||||
uint32_t
|
||||
gpio_adc_sample(struct gpio_adc g)
|
||||
{
|
||||
uint32_t chsr = ADC->ADC_CHSR & 0xffff;
|
||||
if (!chsr) {
|
||||
// Start sample
|
||||
ADC->ADC_CHER = g.bit;
|
||||
ADC->ADC_CR = ADC_CR_START;
|
||||
goto need_delay;
|
||||
}
|
||||
if (chsr != g.bit)
|
||||
// Sampling in progress on another channel
|
||||
goto need_delay;
|
||||
if (!(ADC->ADC_ISR & ADC_ISR_DRDY))
|
||||
// Conversion still in progress
|
||||
goto need_delay;
|
||||
// Conversion ready
|
||||
return 0;
|
||||
need_delay:
|
||||
return ADC_FREQ_MAX * 1000ULL / CONFIG_CLOCK_FREQ;
|
||||
}
|
||||
|
||||
// Read a value; use only after gpio_adc_sample() returns zero
|
||||
uint16_t
|
||||
gpio_adc_read(struct gpio_adc g)
|
||||
{
|
||||
ADC->ADC_CHDR = g.bit;
|
||||
return ADC->ADC_LCDR;
|
||||
}
|
||||
|
||||
// Cancel a sample that may have been started with gpio_adc_sample()
|
||||
void
|
||||
gpio_adc_cancel_sample(struct gpio_adc g)
|
||||
{
|
||||
irqstatus_t flag = irq_save();
|
||||
if ((ADC->ADC_CHSR & 0xffff) == g.bit)
|
||||
gpio_adc_read(g);
|
||||
irq_restore(flag);
|
||||
}
|
||||
133
src/sam3/gpio.c
Normal file
133
src/sam3/gpio.c
Normal file
@@ -0,0 +1,133 @@
|
||||
// GPIO functions on sam3x8e
|
||||
//
|
||||
// Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "board/irq.h" // irq_save
|
||||
#include "command.h" // shutdown
|
||||
#include "compiler.h" // ARRAY_SIZE
|
||||
#include "gpio.h" // gpio_out_setup
|
||||
#include "internal.h" // gpio_peripheral
|
||||
#include "sam3x8e.h" // Pio
|
||||
#include "sched.h" // sched_shutdown
|
||||
|
||||
static Pio * const digital_regs[] = {
|
||||
PIOA, PIOB, PIOC, PIOD
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Pin multiplexing
|
||||
****************************************************************/
|
||||
|
||||
void
|
||||
gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up)
|
||||
{
|
||||
uint32_t bank = GPIO2PORT(gpio), bit = GPIO2BIT(gpio);
|
||||
Pio *regs = digital_regs[bank];
|
||||
if (ptype == 'A')
|
||||
regs->PIO_ABSR &= ~bit;
|
||||
else
|
||||
regs->PIO_ABSR |= bit;
|
||||
if (pull_up > 0)
|
||||
regs->PIO_PUER = bit;
|
||||
else
|
||||
regs->PIO_PUDR = bit;
|
||||
regs->PIO_PDR = bit;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* General Purpose Input Output (GPIO) pins
|
||||
****************************************************************/
|
||||
|
||||
struct gpio_out
|
||||
gpio_out_setup(uint8_t pin, uint8_t val)
|
||||
{
|
||||
if (GPIO2PORT(pin) >= ARRAY_SIZE(digital_regs))
|
||||
goto fail;
|
||||
Pio *regs = digital_regs[GPIO2PORT(pin)];
|
||||
struct gpio_out g = { .regs=regs, .bit=GPIO2BIT(pin) };
|
||||
gpio_out_reset(g, val);
|
||||
return g;
|
||||
fail:
|
||||
shutdown("Not an output pin");
|
||||
}
|
||||
|
||||
void
|
||||
gpio_out_reset(struct gpio_out g, uint8_t val)
|
||||
{
|
||||
Pio *regs = g.regs;
|
||||
irqstatus_t flag = irq_save();
|
||||
if (val)
|
||||
regs->PIO_SODR = g.bit;
|
||||
else
|
||||
regs->PIO_CODR = g.bit;
|
||||
regs->PIO_OER = g.bit;
|
||||
regs->PIO_OWER = g.bit;
|
||||
regs->PIO_PER = g.bit;
|
||||
regs->PIO_PUDR = g.bit;
|
||||
irq_restore(flag);
|
||||
}
|
||||
|
||||
void
|
||||
gpio_out_toggle_noirq(struct gpio_out g)
|
||||
{
|
||||
Pio *regs = g.regs;
|
||||
regs->PIO_ODSR ^= g.bit;
|
||||
}
|
||||
|
||||
void
|
||||
gpio_out_toggle(struct gpio_out g)
|
||||
{
|
||||
irqstatus_t flag = irq_save();
|
||||
gpio_out_toggle_noirq(g);
|
||||
irq_restore(flag);
|
||||
}
|
||||
|
||||
void
|
||||
gpio_out_write(struct gpio_out g, uint8_t val)
|
||||
{
|
||||
Pio *regs = g.regs;
|
||||
if (val)
|
||||
regs->PIO_SODR = g.bit;
|
||||
else
|
||||
regs->PIO_CODR = g.bit;
|
||||
}
|
||||
|
||||
|
||||
struct gpio_in
|
||||
gpio_in_setup(uint8_t pin, int8_t pull_up)
|
||||
{
|
||||
if (GPIO2PORT(pin) >= ARRAY_SIZE(digital_regs))
|
||||
goto fail;
|
||||
uint32_t port = GPIO2PORT(pin);
|
||||
PMC->PMC_PCER0 = 1 << (ID_PIOA + port);
|
||||
struct gpio_in g = { .regs=digital_regs[port], .bit=GPIO2BIT(pin) };
|
||||
gpio_in_reset(g, pull_up);
|
||||
return g;
|
||||
fail:
|
||||
shutdown("Not an input pin");
|
||||
}
|
||||
|
||||
void
|
||||
gpio_in_reset(struct gpio_in g, int8_t pull_up)
|
||||
{
|
||||
Pio *regs = g.regs;
|
||||
irqstatus_t flag = irq_save();
|
||||
if (pull_up)
|
||||
regs->PIO_PUER = g.bit;
|
||||
else
|
||||
regs->PIO_PUDR = g.bit;
|
||||
regs->PIO_ODR = g.bit;
|
||||
regs->PIO_PER = g.bit;
|
||||
irq_restore(flag);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
gpio_in_read(struct gpio_in g)
|
||||
{
|
||||
Pio *regs = g.regs;
|
||||
return !!(regs->PIO_PDSR & g.bit);
|
||||
}
|
||||
40
src/sam3/gpio.h
Normal file
40
src/sam3/gpio.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef __SAM3_GPIO_H
|
||||
#define __SAM3_GPIO_H
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
struct gpio_out {
|
||||
void *regs;
|
||||
uint32_t bit;
|
||||
};
|
||||
struct gpio_out gpio_out_setup(uint8_t pin, uint8_t val);
|
||||
void gpio_out_reset(struct gpio_out g, uint8_t val);
|
||||
void gpio_out_toggle_noirq(struct gpio_out g);
|
||||
void gpio_out_toggle(struct gpio_out g);
|
||||
void gpio_out_write(struct gpio_out g, uint8_t val);
|
||||
|
||||
struct gpio_in {
|
||||
void *regs;
|
||||
uint32_t bit;
|
||||
};
|
||||
struct gpio_in gpio_in_setup(uint8_t pin, int8_t pull_up);
|
||||
void gpio_in_reset(struct gpio_in g, int8_t pull_up);
|
||||
uint8_t gpio_in_read(struct gpio_in g);
|
||||
|
||||
struct gpio_adc {
|
||||
uint32_t bit;
|
||||
};
|
||||
struct gpio_adc gpio_adc_setup(uint8_t pin);
|
||||
uint32_t gpio_adc_sample(struct gpio_adc g);
|
||||
uint16_t gpio_adc_read(struct gpio_adc g);
|
||||
void gpio_adc_cancel_sample(struct gpio_adc g);
|
||||
|
||||
struct spi_config {
|
||||
uint32_t cfg;
|
||||
};
|
||||
struct spi_config spi_setup(uint32_t bus, uint8_t mode, uint32_t rate);
|
||||
void spi_prepare(struct spi_config config);
|
||||
void spi_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data);
|
||||
|
||||
#endif // gpio.h
|
||||
13
src/sam3/internal.h
Normal file
13
src/sam3/internal.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __SAM3_INTERNAL_H
|
||||
#define __SAM3_INTERNAL_H
|
||||
// Local definitions for sam3 code
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#define GPIO(PORT, NUM) (((PORT)-'A') * 32 + (NUM))
|
||||
#define GPIO2PORT(PIN) ((PIN) / 32)
|
||||
#define GPIO2BIT(PIN) (1<<((PIN) % 32))
|
||||
|
||||
void gpio_peripheral(uint32_t gpio, char ptype, int32_t pull_up);
|
||||
|
||||
#endif // internal.h
|
||||
52
src/sam3/main.c
Normal file
52
src/sam3/main.c
Normal file
@@ -0,0 +1,52 @@
|
||||
// Main starting point for SAM3x8e boards.
|
||||
//
|
||||
// Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "command.h" // DECL_CONSTANT
|
||||
#include "sam3x8e.h" // WDT
|
||||
#include "sched.h" // sched_main
|
||||
|
||||
DECL_CONSTANT(MCU, "sam3x8e");
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* watchdog handler
|
||||
****************************************************************/
|
||||
|
||||
void
|
||||
watchdog_reset(void)
|
||||
{
|
||||
WDT->WDT_CR = 0xA5000001;
|
||||
}
|
||||
DECL_TASK(watchdog_reset);
|
||||
|
||||
void
|
||||
watchdog_init(void)
|
||||
{
|
||||
uint32_t timeout = 500 * 32768 / 128 / 1000; // 500ms timeout
|
||||
WDT->WDT_MR = WDT_MR_WDRSTEN | WDT_MR_WDV(timeout) | WDT_MR_WDD(timeout);
|
||||
}
|
||||
DECL_INIT(watchdog_init);
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* misc functions
|
||||
****************************************************************/
|
||||
|
||||
void
|
||||
command_reset(uint32_t *args)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
DECL_COMMAND_FLAGS(command_reset, HF_IN_SHUTDOWN, "reset");
|
||||
|
||||
// Main entry point
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
SystemInit();
|
||||
sched_main();
|
||||
return 0;
|
||||
}
|
||||
56
src/sam3/serial.c
Normal file
56
src/sam3/serial.c
Normal file
@@ -0,0 +1,56 @@
|
||||
// sam3x8e serial port
|
||||
//
|
||||
// Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "autoconf.h" // CONFIG_SERIAL_BAUD
|
||||
#include "board/serial_irq.h" // serial_rx_data
|
||||
#include "internal.h" // gpio_peripheral
|
||||
#include "sam3x8e.h" // UART
|
||||
#include "sched.h" // DECL_INIT
|
||||
|
||||
void
|
||||
serial_init(void)
|
||||
{
|
||||
gpio_peripheral(GPIO('A', 8), 'A', 1);
|
||||
gpio_peripheral(GPIO('A', 9), 'A', 0);
|
||||
|
||||
// Reset uart
|
||||
PMC->PMC_PCER0 = 1 << ID_UART;
|
||||
UART->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
|
||||
UART->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS;
|
||||
UART->UART_IDR = 0xFFFFFFFF;
|
||||
|
||||
// Enable uart
|
||||
UART->UART_MR = (US_MR_CHRL_8_BIT | US_MR_NBSTOP_1_BIT | UART_MR_PAR_NO
|
||||
| UART_MR_CHMODE_NORMAL);
|
||||
UART->UART_BRGR = SystemCoreClock / (16 * CONFIG_SERIAL_BAUD);
|
||||
UART->UART_IER = UART_IER_RXRDY;
|
||||
NVIC_EnableIRQ(UART_IRQn);
|
||||
NVIC_SetPriority(UART_IRQn, 0);
|
||||
UART->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
|
||||
}
|
||||
DECL_INIT(serial_init);
|
||||
|
||||
void __visible
|
||||
UART_Handler(void)
|
||||
{
|
||||
uint32_t status = UART->UART_SR;
|
||||
if (status & UART_SR_RXRDY)
|
||||
serial_rx_byte(UART->UART_RHR);
|
||||
if (status & UART_SR_TXRDY) {
|
||||
uint8_t data;
|
||||
int ret = serial_get_tx_byte(&data);
|
||||
if (ret)
|
||||
UART->UART_IDR = UART_IDR_TXRDY;
|
||||
else
|
||||
UART->UART_THR = data;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
serial_enable_tx_irq(void)
|
||||
{
|
||||
UART->UART_IER = UART_IDR_TXRDY;
|
||||
}
|
||||
129
src/sam3/spi.c
Normal file
129
src/sam3/spi.c
Normal file
@@ -0,0 +1,129 @@
|
||||
// SPI transmissions on sam3x8e
|
||||
//
|
||||
// Copyright (C) 2018 Petri Honkala <cruwaller@gmail.com>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include <sam3x8e.h> // REGPTR
|
||||
#include "command.h" // shutdown
|
||||
#include "gpio.h" // spi_setup
|
||||
#include "internal.h" // gpio_peripheral
|
||||
#include "sched.h" // sched_shutdown
|
||||
|
||||
#define REGPTR SPI0
|
||||
#define PERIPH_ID ID_SPI0
|
||||
|
||||
#define CHANNEL 0 // Use same channel for all
|
||||
|
||||
static void
|
||||
spi_init(void)
|
||||
{
|
||||
/* Configure SCK, MISO and MOSI */
|
||||
gpio_peripheral(GPIO('A', 25), 'A', 0); // Arduino 74
|
||||
gpio_peripheral(GPIO('A', 26), 'A', 0); // Arduino 75
|
||||
gpio_peripheral(GPIO('A', 27), 'A', 0); // Arduino 76
|
||||
|
||||
// Enable SPI clocks
|
||||
if (!(PMC->PMC_PCSR0 & (1u << PERIPH_ID))) {
|
||||
PMC->PMC_PCER0 = (1 << PERIPH_ID);
|
||||
}
|
||||
|
||||
/* Disable SPI */
|
||||
REGPTR->SPI_CR = SPI_CR_SPIDIS;
|
||||
/* Execute a software reset of the SPI twice */
|
||||
REGPTR->SPI_CR = SPI_CR_SWRST;
|
||||
REGPTR->SPI_CR = SPI_CR_SWRST;
|
||||
|
||||
REGPTR->SPI_MR = ( SPI_MR_MSTR | // Set master mode
|
||||
SPI_MR_MODFDIS | // Disable fault detection
|
||||
SPI_MR_PCS(CHANNEL) // Fixes peripheral select
|
||||
);
|
||||
REGPTR->SPI_IDR = 0xffffffff; // Disable ISRs
|
||||
|
||||
/* Clear Chip Select Registers */
|
||||
REGPTR->SPI_CSR[0] = 0;
|
||||
REGPTR->SPI_CSR[1] = 0;
|
||||
REGPTR->SPI_CSR[2] = 0;
|
||||
REGPTR->SPI_CSR[3] = 0;
|
||||
|
||||
/* Set basic channel config */
|
||||
REGPTR->SPI_CSR[CHANNEL] = 0;
|
||||
/* Enable SPI */
|
||||
REGPTR->SPI_CR = SPI_CR_SPIEN;
|
||||
}
|
||||
|
||||
struct spi_config
|
||||
spi_setup(uint32_t bus, uint8_t mode, uint32_t rate)
|
||||
{
|
||||
if (bus != CHANNEL)
|
||||
shutdown("Invalid spi_setup parameters");
|
||||
|
||||
// Make sure bus is enabled
|
||||
spi_init();
|
||||
|
||||
uint32_t config = 0;
|
||||
uint32_t clockDiv;
|
||||
if (rate < (CHIP_FREQ_CPU_MAX / 255)) {
|
||||
clockDiv = 255;
|
||||
} else if (rate >= (CHIP_FREQ_CPU_MAX / 2)) {
|
||||
clockDiv = 2;
|
||||
} else {
|
||||
clockDiv = (CHIP_FREQ_CPU_MAX / (rate + 1)) + 1;
|
||||
}
|
||||
|
||||
/****** Will be written to SPI_CSRx register ******/
|
||||
// CSAAT : Chip Select Active After Transfer
|
||||
config = SPI_CSR_CSAAT;
|
||||
config |= SPI_CSR_BITS_8_BIT; // TODO: support for SPI_CSR_BITS_16_BIT
|
||||
// NOTE: NCPHA is inverted, CPHA normal!!
|
||||
switch(mode) {
|
||||
case 0:
|
||||
config |= SPI_CSR_NCPHA;
|
||||
break;
|
||||
case 1:
|
||||
config |= 0;
|
||||
break;
|
||||
case 2:
|
||||
config |= SPI_CSR_NCPHA;
|
||||
config |= SPI_CSR_CPOL;
|
||||
break;
|
||||
case 3:
|
||||
config |= SPI_CSR_CPOL;
|
||||
break;
|
||||
};
|
||||
|
||||
config |= ((clockDiv & 0xffu) << SPI_CSR_SCBR_Pos);
|
||||
return (struct spi_config){.cfg = config};
|
||||
}
|
||||
|
||||
void
|
||||
spi_prepare(struct spi_config config)
|
||||
{
|
||||
REGPTR->SPI_CSR[CHANNEL] = config.cfg;
|
||||
}
|
||||
|
||||
void
|
||||
spi_transfer(struct spi_config config, uint8_t receive_data
|
||||
, uint8_t len, uint8_t *data)
|
||||
{
|
||||
Spi* const pSpi = REGPTR;
|
||||
if (receive_data) {
|
||||
while (len--) {
|
||||
pSpi->SPI_TDR = *data;
|
||||
// wait for receive register
|
||||
while (!(pSpi->SPI_SR & SPI_SR_RDRF))
|
||||
;
|
||||
// get data
|
||||
*data++ = pSpi->SPI_RDR;
|
||||
}
|
||||
} else {
|
||||
while (len--) {
|
||||
pSpi->SPI_TDR = *data++;
|
||||
// wait for receive register
|
||||
while (!(pSpi->SPI_SR & SPI_SR_RDRF))
|
||||
;
|
||||
// read data (to clear RDRF)
|
||||
pSpi->SPI_RDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/sam3/timer.c
Normal file
65
src/sam3/timer.c
Normal file
@@ -0,0 +1,65 @@
|
||||
// SAM3x8e timer interrupt scheduling
|
||||
//
|
||||
// Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net>
|
||||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include "board/irq.h" // irq_disable
|
||||
#include "board/misc.h" // timer_read_time
|
||||
#include "board/timer_irq.h" // timer_dispatch_many
|
||||
#include "command.h" // DECL_SHUTDOWN
|
||||
#include "sam3x8e.h" // TC0
|
||||
#include "sched.h" // DECL_INIT
|
||||
|
||||
// Set the next irq time
|
||||
static void
|
||||
timer_set(uint32_t value)
|
||||
{
|
||||
TC0->TC_CHANNEL[0].TC_RA = value;
|
||||
}
|
||||
|
||||
// Return the current time (in absolute clock ticks).
|
||||
uint32_t
|
||||
timer_read_time(void)
|
||||
{
|
||||
return TC0->TC_CHANNEL[0].TC_CV;
|
||||
}
|
||||
|
||||
// Activate timer dispatch as soon as possible
|
||||
void
|
||||
timer_kick(void)
|
||||
{
|
||||
timer_set(timer_read_time() + 50);
|
||||
TC0->TC_CHANNEL[0].TC_SR; // read to clear irq pending
|
||||
}
|
||||
|
||||
void
|
||||
timer_init(void)
|
||||
{
|
||||
TcChannel *tc = &TC0->TC_CHANNEL[0];
|
||||
// Reset the timer
|
||||
tc->TC_CCR = TC_CCR_CLKDIS;
|
||||
tc->TC_IDR = 0xFFFFFFFF;
|
||||
// Enable it
|
||||
PMC->PMC_PCER0 = 1 << ID_TC0;
|
||||
tc->TC_CMR = TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1;
|
||||
tc->TC_IER = TC_IER_CPAS;
|
||||
NVIC_SetPriority(TC0_IRQn, 1);
|
||||
NVIC_EnableIRQ(TC0_IRQn);
|
||||
timer_kick();
|
||||
tc->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
|
||||
}
|
||||
DECL_INIT(timer_init);
|
||||
|
||||
// IRQ handler
|
||||
void __visible __aligned(16) // aligning helps stabilize perf benchmarks
|
||||
TC0_Handler(void)
|
||||
{
|
||||
irq_disable();
|
||||
uint32_t status = TC0->TC_CHANNEL[0].TC_SR; // read to clear irq pending
|
||||
if (likely(status & TC_SR_CPAS)) {
|
||||
uint32_t next = timer_dispatch_many();
|
||||
timer_set(next);
|
||||
}
|
||||
irq_enable();
|
||||
}
|
||||
Reference in New Issue
Block a user