SPI, RTC, Serial changes

- SPI - implementation
	- RTC - there's 32.768kHz crystal, use that as a source
	- Serial - 10bit transfer
pull/135/head
0xc0170 2013-12-23 19:57:10 +01:00
parent 988894e837
commit 366221524a
7 changed files with 148 additions and 133 deletions

View File

@ -52,7 +52,7 @@ void analogin_init(analogin_t *obj, PinName pin) {
| ADC_CFG1_MODE(3) // (16)bits Resolution
| ADC_CFG1_ADICLK(1); // Input Clock: (Bus Clock)/2
ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels
ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels
| ADC_CFG2_ADACKEN_MASK // Asynchronous Clock Output Enable
| ADC_CFG2_ADHSC_MASK // High-Speed Configuration
| ADC_CFG2_ADLSTS(0); // Long Sample Time Select

View File

@ -22,7 +22,8 @@ uint32_t gpio_set(PinName pin) {
}
void gpio_init(gpio_t *obj, PinName pin, PinDirection direction) {
if(pin == NC) return;
if(pin == NC)
return;
obj->pin = pin;
obj->mask = gpio_set(pin);
@ -37,8 +38,12 @@ void gpio_init(gpio_t *obj, PinName pin, PinDirection direction) {
gpio_dir(obj, direction);
switch (direction) {
case PIN_OUTPUT: pin_mode(pin, PullNone); break;
case PIN_INPUT : pin_mode(pin, PullUp); break;
case PIN_OUTPUT:
pin_mode(pin, PullNone);
break;
case PIN_INPUT :
pin_mode(pin, PullUp);
break;
}
}
@ -48,7 +53,11 @@ void gpio_mode(gpio_t *obj, PinMode mode) {
void gpio_dir(gpio_t *obj, PinDirection direction) {
switch (direction) {
case PIN_INPUT : *obj->reg_dir &= ~obj->mask; break;
case PIN_OUTPUT: *obj->reg_dir |= obj->mask; break;
case PIN_INPUT :
*obj->reg_dir &= ~obj->mask;
break;
case PIN_OUTPUT:
*obj->reg_dir |= obj->mask;
break;
}
}

View File

@ -53,7 +53,6 @@ static void handle_interrupt_in(PORT_Type *port, int ch_base) {
case IRQ_EITHER_EDGE:
gpio += (port_num * 0x40);
//gpio = (port == PORTA) ? (PTA) : (PTD);
event = (gpio->PDIR & pmask) ? (IRQ_RISE) : (IRQ_FALL);
break;
}
@ -82,23 +81,32 @@ int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32
IRQn_Type irq_n;
switch (obj->port) {
case PortA:
ch_base = 0; irq_n = PORTA_IRQn; vector = (uint32_t)gpio_irqA;
ch_base = 0;
irq_n = PORTA_IRQn;
vector = (uint32_t)gpio_irqA;
break;
case PortB:
ch_base = 0; irq_n = PORTB_IRQn; vector = (uint32_t)gpio_irqB;
ch_base = 32;
irq_n = PORTB_IRQn;
vector = (uint32_t)gpio_irqB;
break;
case PortC:
ch_base = 0; irq_n = PORTC_IRQn; vector = (uint32_t)gpio_irqC;
ch_base = 64;
irq_n = PORTC_IRQn;
vector = (uint32_t)gpio_irqC;
break;
case PortD:
ch_base = 32; irq_n = PORTD_IRQn; vector = (uint32_t)gpio_irqD;
ch_base = 96;
irq_n = PORTD_IRQn; vector = (uint32_t)gpio_irqD;
break;
case PortE:
ch_base = 0; irq_n = PORTE_IRQn; vector = (uint32_t)gpio_irqE;
ch_base = 128;
irq_n = PORTE_IRQn;
vector = (uint32_t)gpio_irqE;
break;
default:
error("gpio_irq only supported on port A and D\n");
error("gpio_irq only supported on port A-E.\n");
break;
}
NVIC_SetVector(irq_n, vector);

View File

@ -22,23 +22,17 @@ static void init(void) {
// enable RTC clock
SIM->SCGC6 |= SIM_SCGC6_RTC_MASK;
/*
* configure PTC1 with alternate function 1: RTC_CLKIN
* As the kl25z board does not have a 32kHz osc,
* we use an external clock generated by the
* interface chip
*/
PORTC->PCR[1] &= ~PORT_PCR_MUX_MASK;
PORTC->PCR[1] = PORT_PCR_MUX(1);
// select RTC_CLKIN as RTC clock source
// OSC32 as source
SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK;
SIM->SOPT1 |= SIM_SOPT1_OSC32KSEL(2);
SIM->SOPT1 |= SIM_SOPT1_OSC32KSEL(0);
}
void rtc_init(void) {
init();
// Enable the oscillator
RTC_CR |= RTC_CR_OSCE_MASK;
//Configure the TSR. default value: 1
RTC->TSR = 1;

View File

@ -24,20 +24,18 @@
#include "pinmap.h"
#include "error.h"
/******************************************************************************
* INITIALIZATION
******************************************************************************/
static const PinMap PinMap_UART_TX[] = {
{PTB17, UART_0, 3},
{PTB17, UART_0, 3},
{NC , NC , 0}
};
static const PinMap PinMap_UART_RX[] = {
{PTB16, UART_0, 3},
{PTB16, UART_0, 3},
{NC , NC , 0}
};
#define UART_NUM 3
static uint32_t serial_irq_ids[UART_NUM] = {0};
static uart_irq_handler irq_handler;
@ -49,9 +47,8 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
if ((int)uart == NC) {
if ((int)uart == NC)
error("Serial pinout mapping failed");
}
obj->uart = (UART_Type *)uart;
// enable clk
@ -63,7 +60,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
}
// Disable UART before changing registers
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
switch (uart) {
case UART_0: obj->index = 0; break;
case UART_1: obj->index = 1; break;
@ -94,27 +91,13 @@ void serial_free(serial_t *obj) {
serial_irq_ids[obj->index] = 0;
}
// serial_baud
//
// set the baud rate, taking in to account the current SystemFrequency
//
// The LPC2300 and LPC1700 have a divider and a fractional divider to control the
// baud rate. The formula is:
//
// Baudrate = (1 / PCLK) * 16 * DL * (1 + DivAddVal / MulVal)
// where:
// 1 < MulVal <= 15
// 0 <= DivAddVal < 14
// DivAddVal < MulVal
//
void serial_baud(serial_t *obj, int baudrate) {
// save C2 state
uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
uint32_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
// Disable UART before changing registers
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
// [TODO] not hardcode this value
uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u;
@ -129,27 +112,26 @@ void serial_baud(serial_t *obj, int baudrate) {
// set BDH and BDL
obj->uart->BDH = (obj->uart->BDH & ~(0x1f)) | ((DL >> 8) & 0x1f);
obj->uart->BDL = (obj->uart->BDL & ~(0xff)) | ((DL >> 0) & 0xff);
// restore C2 state
obj->uart->C2 |= c2_state;
}
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
// uint8_t m10 = 0;
// save C2 state
uint8_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
uint32_t c2_state = (obj->uart->C2 & (UART_C2_RE_MASK | UART_C2_TE_MASK));
// Disable UART before changing registers
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
// 8 data bits = 0 ... 9 data bits = 1
if ((data_bits < 8) || (data_bits > 9)) {
if ((data_bits < 8) || (data_bits > 9))
error("Invalid number of bits (%d) in serial format, should be 8..9\r\n", data_bits);
}
data_bits -= 8;
uint8_t parity_enable, parity_select;
uint32_t parity_enable, parity_select;
switch (parity) {
case ParityNone: parity_enable = 0; parity_select = 0; break;
case ParityOdd : parity_enable = 1; parity_select = 1; data_bits++; break;
@ -160,36 +142,36 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
}
// 1 stop bits = 0, 2 stop bits = 1
if ((stop_bits != 1) && (stop_bits != 2)) {
if ((stop_bits != 1) && (stop_bits != 2))
error("Invalid stop bits specified\r\n");
}
stop_bits -= 1;
uint32_t m10 = 0;
// 9 data bits + parity
if (data_bits == 2) {
// only uart0 supports 10 bit communication
if (obj->index != 0) {
if (obj->index != 0)
error("Invalid number of bits (9) to be used with parity\r\n");
}
data_bits = 0;
//m10 = 1;
m10 = 1;
}
// data bits, parity and parity mode
obj->uart->C1 = ((data_bits << 4)
| (parity_enable << 1)
| (parity_select << 0));
// enable 10bit mode if needed
// if (obj->index == 0) {
// obj->uart->C4 &= ~UARTLP_C4_M10_MASK;
// obj->uart->C4 |= (m10 << UARTLP_C4_M10_SHIFT);
// }
//enable 10bit mode if needed
if (obj->index == 0) {
obj->uart->C4 &= ~UART_C4_M10_MASK;
obj->uart->C4 |= (m10 << UART_C4_M10_SHIFT);
}
// stop bits
obj->uart->BDH &= ~UART_BDH_SBR_MASK;
obj->uart->BDH |= (stop_bits << UART_BDH_SBR_SHIFT);
// restore C2 state
obj->uart->C2 |= c2_state;
}
@ -220,15 +202,28 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
IRQn_Type irq_n = (IRQn_Type)0;
uint32_t vector = 0;
switch ((int)obj->uart) {
case UART_0: irq_n=UART0_RX_TX_IRQn; vector = (uint32_t)&uart0_irq; break;
case UART_1: irq_n=UART1_RX_TX_IRQn; vector = (uint32_t)&uart1_irq; break;
case UART_2: irq_n=UART2_RX_TX_IRQn; vector = (uint32_t)&uart2_irq; break;
case UART_0:
irq_n=UART0_RX_TX_IRQn;
vector = (uint32_t)&uart0_irq;
break;
case UART_1:
irq_n=UART1_RX_TX_IRQn;
vector = (uint32_t)&uart1_irq;
break;
case UART_2:
irq_n=UART2_RX_TX_IRQn;
vector = (uint32_t)&uart2_irq;
break;
}
if (enable) {
switch (irq) {
case RxIrq: obj->uart->C2 |= (UART_C2_RIE_MASK); break;
case TxIrq: obj->uart->C2 |= (UART_C2_TIE_MASK); break;
case RxIrq:
obj->uart->C2 |= (UART_C2_RIE_MASK);
break;
case TxIrq:
obj->uart->C2 |= (UART_C2_TIE_MASK);
break;
}
NVIC_SetVector(irq_n, vector);
NVIC_EnableIRQ(irq_n);
@ -237,21 +232,26 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
int all_disabled = 0;
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
switch (irq) {
case RxIrq: obj->uart->C2 &= ~(UART_C2_RIE_MASK); break;
case TxIrq: obj->uart->C2 &= ~(UART_C2_TIE_MASK); break;
case RxIrq:
obj->uart->C2 &= ~(UART_C2_RIE_MASK);
break;
case TxIrq:
obj->uart->C2 &= ~(UART_C2_TIE_MASK);
break;
}
switch (other_irq) {
case RxIrq: all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0; break;
case TxIrq: all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0; break;
case RxIrq:
all_disabled = (obj->uart->C2 & (UART_C2_RIE_MASK)) == 0;
break;
case TxIrq:
all_disabled = (obj->uart->C2 & (UART_C2_TIE_MASK)) == 0;
break;
}
if (all_disabled)
NVIC_DisableIRQ(irq_n);
}
}
/******************************************************************************
* READ/WRITE
******************************************************************************/
int serial_getc(serial_t *obj) {
while (!serial_readable(obj));
return obj->uart->D;
@ -263,7 +263,7 @@ void serial_putc(serial_t *obj, int c) {
}
int serial_readable(serial_t *obj) {
return (obj->uart->S1 & UART_S1_RDRF_MASK);
}
@ -280,7 +280,7 @@ void serial_pinout_tx(PinName tx) {
}
void serial_break_set(serial_t *obj) {
obj->uart->C2 |= UART_C2_SBK_MASK;
obj->uart->C2 |= UART_C2_SBK_MASK;
}
void serial_break_clear(serial_t *obj) {

View File

@ -1,5 +1,5 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
* Copyright (c) 2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,25 +24,25 @@
static const PinMap PinMap_SPI_SCLK[] = {
{PTC5, SPI_0, 2},
{PTD1, SPI_0, 2},
{NC , NC , 0}
{NC , NC , 0}
};
static const PinMap PinMap_SPI_MOSI[] = {
{PTD2, SPI_0, 2},
{PTC6, SPI_0, 2},
{NC , NC , 0}
{NC , NC , 0}
};
static const PinMap PinMap_SPI_MISO[] = {
{PTD3, SPI_0, 2},
{PTC7, SPI_0, 2},
{NC , NC , 0}
{NC , NC , 0}
};
static const PinMap PinMap_SPI_SSEL[] = {
{PTD0, SPI_0, 2},
{PTC4, SPI_0, 2},
{NC , NC , 0}
{NC , NC , 0}
};
void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
@ -59,10 +59,11 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
error("SPI pinout mapping failed");
}
// enable power and clocking
switch ((int)obj->spi) {
case SPI_0: SIM->SCGC5 |= 1 << 11; SIM->SCGC4 |= 1 << 22; break;
}
SIM->SCGC5 |= (1 << 11) | (1 << 12); // PortC & D
SIM->SCGC6 |= 1 << 12; // spi clocks
// halted state
obj->spi->MCR = SPI_MCR_HALT_MASK;
// set default format and frequency
if (ssel == NC) {
@ -72,8 +73,10 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
}
spi_frequency(obj, 1000000);
// not halt in the debug mode
obj->spi->SR |= SPI_SR_EOQF_MASK;
// enable SPI
obj->spi->MCR |= SPI_MCR_CONT_SCKE_MASK;
obj->spi->MCR &= (~SPI_MCR_HALT_MASK);
// pin out the spi pins
pinmap_pinout(mosi, PinMap_SPI_MOSI);
@ -88,37 +91,38 @@ void spi_free(spi_t *obj) {
// [TODO]
}
void spi_format(spi_t *obj, int bits, int mode, int slave) {
if (bits != 8) {
error("Only 8bits SPI supported");
if ((bits != 8) && (bits != 16)) {
error("Only 8/16 bits SPI supported");
}
if ((mode < 0) || (mode > 3)) {
error("SPI mode unsupported");
}
uint8_t polarity = (mode & 0x2) ? 1 : 0;
uint8_t phase = (mode & 0x1) ? 1 : 0;
uint8_t c1_data = ((!slave) << 4) | (polarity << 3) | (phase << 2);
uint32_t polarity = (mode & 0x2) ? 1 : 0;
uint32_t phase = (mode & 0x1) ? 1 : 0;
// clear MSTR, CPOL and CPHA bits
// set master/slave
obj->spi->MCR &= ~SPI_MCR_MSTR_MASK;
obj->spi->MCR |= ((!slave) << SPI_MCR_MSTR_SHIFT);
// write new value
obj->spi->MCR |= c1_data;
// CTAR0 is used
obj->spi->CTAR[0] &= ~(SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK);
obj->spi->CTAR[0] |= (polarity << SPI_CTAR_CPOL_SHIFT) | (phase << SPI_CTAR_CPHA_SHIFT);
}
void spi_frequency(spi_t *obj, int hz) {
uint32_t error = 0;
uint32_t p_error = 0xffffffff;
uint32_t ref = 0;
uint8_t spr = 0;
uint8_t ref_spr = 0;
uint8_t ref_prescaler = 0;
uint32_t spr = 0;
uint32_t ref_spr = 0;
uint32_t ref_prescaler = 0;
// bus clk
uint32_t PCLK = 48000000u;
uint8_t prescaler = 1;
uint8_t divisor = 2;
uint32_t prescaler = 1;
uint32_t divisor = 2;
for (prescaler = 1; prescaler <= 8; prescaler++) {
divisor = 2;
@ -140,32 +144,31 @@ void spi_frequency(spi_t *obj, int hz) {
}
static inline int spi_writeable(spi_t * obj) {
return 0;//(obj->spi->S & SPI_S_SPTEF_MASK) ? 1 : 0;
return (obj->spi->SR & SPI_SR_TCF_MASK) ? 1 : 0;
}
static inline int spi_readable(spi_t * obj) {
return 0;//(obj->spi->S & SPI_S_SPRF_MASK) ? 1 : 0;
return (obj->spi->SR & SPI_SR_TFFF_MASK) ? 1 : 0;
}
int spi_master_write(spi_t *obj, int value) {
// wait tx buffer empty
// while(!spi_writeable(obj));
// obj->spi->D = (value & 0xff);
while(!spi_writeable(obj));
obj->spi->PUSHR = SPI_PUSHR_TXDATA(value & 0xff);
// // wait rx buffer full
// while (!spi_readable(obj));
return 0;//obj->spi->D & 0xff;
// wait rx buffer full
while (!spi_readable(obj));
return obj->spi->POPR;
}
int spi_slave_receive(spi_t *obj) {
return 0;//spi_readable(obj);
return spi_readable(obj);
}
int spi_slave_read(spi_t *obj) {
return 0;//obj->spi->D;
return obj->spi->POPR;
}
void spi_slave_write(spi_t *obj, int value) {
// while (!spi_writeable(obj));
// obj->spi->D = value;
while (!spi_writeable(obj));
}

View File

@ -23,9 +23,10 @@ static void lptmr_init(void);
static int us_ticker_inited = 0;
void us_ticker_init(void) {
if (us_ticker_inited) return;
if (us_ticker_inited)
return;
us_ticker_inited = 1;
pit_init();
lptmr_init();
}
@ -62,7 +63,7 @@ uint32_t us_ticker_read() {
/******************************************************************************
* Timer Event
*
*
* It schedules interrupts at given (32bit)us interval of time.
* It is implemented used the 16bit Low Power Timer that remains powered in all
* power modes.
@ -72,14 +73,14 @@ static void lptmr_isr(void);
static void lptmr_init(void) {
/* Clock the timer */
SIM->SCGC5 |= SIM_SCGC5_LPTIMER_MASK;
/* Reset */
LPTMR0->CSR = 0;
/* Set interrupt handler */
NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr);
NVIC_EnableIRQ(LPTimer_IRQn);
/* Clock at (1)MHz -> (1)tick/us */
LPTMR0->PSR = LPTMR_PSR_PCS(3); // OSCERCLK -> 8MHz
LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8
@ -99,13 +100,13 @@ static uint16_t us_ticker_int_remainder = 0;
static void lptmr_set(unsigned short count) {
/* Reset */
LPTMR0->CSR = 0;
/* Set the compare register */
LPTMR0->CMR = count;
/* Enable interrupt */
LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
/* Start the timer */
LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
}
@ -113,16 +114,16 @@ static void lptmr_set(unsigned short count) {
static void lptmr_isr(void) {
// write 1 to TCF to clear the LPT timer compare flag
LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
if (us_ticker_int_counter > 0) {
lptmr_set(0xFFFF);
us_ticker_int_counter--;
} else {
if (us_ticker_int_remainder > 0) {
lptmr_set(us_ticker_int_remainder);
us_ticker_int_remainder = 0;
} else {
// This function is going to disable the interrupts if there are
// no other events in the queue
@ -138,7 +139,7 @@ void us_ticker_set_interrupt(unsigned int timestamp) {
us_ticker_irq_handler();
return;
}
us_ticker_int_counter = (uint32_t)(delta >> 16);
us_ticker_int_remainder = (uint16_t)(0xFFFF & delta);
if (us_ticker_int_counter > 0) {