summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2014-02-26 21:06:30 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2014-02-26 21:06:30 +0100
commit79b6705bfc60ed17ddbf6c36ead99e9f5c3c7404 (patch)
tree0b11a3c4f39f6a5ba6389b70b0d225ade3b656f5
parent1b6d3f9ee7fad554f23b05d7e4a09c3ec9635636 (diff)
Old SPI code is now disabled, new SPI code succesfully reads out WM8523 chip id. Needs lots of cleaning...
-rw-r--r--firmware/Makefile7
-rw-r--r--firmware/drivers/GPIO.c171
-rw-r--r--firmware/drivers/GPIO.h21
-rw-r--r--firmware/drivers/spi.c35
-rw-r--r--firmware/drivers/ssp.c413
-rw-r--r--firmware/drivers/ssp.h121
-rw-r--r--firmware/drivers/timer.c572
-rw-r--r--firmware/drivers/timer.h47
-rw-r--r--firmware/drivers/wm8523.c12
-rw-r--r--firmware/src/p2m.c152
10 files changed, 1515 insertions, 36 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
index f7edae3..acd193f 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -25,7 +25,7 @@ RM = rm
#Q = # @./quiet "$@"
# Flags
-CFLAGS = -W -Wall -O0 --std=gnu99 -fgnu89-inline -mcpu=cortex-m3 -mthumb
+CFLAGS = -W -Wall -Werror -O0 --std=gnu99 -fgnu89-inline -mcpu=cortex-m3 -mthumb
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -I${LPC} -I${DRV}
ASFLAGS =
@@ -45,7 +45,10 @@ LINKER_SCRIPT = ${LPC}/LPC17xx.ld
CSRCS = \
${LPC}/startup_LPC17xx.c \
${LPC}/system_LPC17xx.c \
- $(wildcard ${SRC}/*.c)
+ ${LPC}/lpc17xx_spi.c \
+ ${LPC}/lpc17xx_clkpwr.c \
+ $(wildcard ${SRC}/*.c) \
+ $(wildcard ${DRV}/*.c)
# ${DRV}/*.c \
diff --git a/firmware/drivers/GPIO.c b/firmware/drivers/GPIO.c
new file mode 100644
index 0000000..f89b038
--- /dev/null
+++ b/firmware/drivers/GPIO.c
@@ -0,0 +1,171 @@
+#include <LPC17xx.h>
+
+//#include "lpc_types.h"
+#define FALSE 0
+#define TRUE 1
+
+#include "GPIO.h"
+
+static LPC_GPIO_TypeDef (* const LPC_GPIO[5]) = { LPC_GPIO0, LPC_GPIO1, LPC_GPIO2, LPC_GPIO3, LPC_GPIO4 };
+
+
+void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal )
+{
+ if (bitVal == 0)
+ {
+ LPC_GPIO[portNum]->FIOCLR = (1<<bitPosi);
+ }
+ else if (bitVal >= 1)
+ {
+ LPC_GPIO[portNum]->FIOSET = (1<<bitPosi);
+ }
+}
+
+void GPIOSetDir( uint32_t portNum, uint32_t bitPosi, uint32_t dir )
+{
+ if(dir)
+ LPC_GPIO[portNum]->FIODIR |= 1<<bitPosi;
+ else
+ LPC_GPIO[portNum]->FIODIR &= ~(1<<bitPosi);
+}
+
+void GPIOSetPull( uint32_t portNum, uint32_t bitPosi, uint32_t dir)
+{
+
+ if (dir == 0) { //no Pull
+ dir = 10;
+ } else if(dir == 1){ //Pull up
+ dir = 00;
+ } else if(dir == 2){ //Pull down
+ dir = 11;
+ }
+
+ switch (portNum)
+ {
+ case 0:
+
+ if (bitPosi < 16 ) {
+ bitPosi = bitPosi * 2;
+ LPC_PINCON->PINMODE0 |= dir<<bitPosi;
+ } else if (bitPosi > 15){
+ bitPosi = bitPosi - 16;
+ bitPosi = bitPosi * 2;
+ LPC_PINCON->PINMODE1 |= dir<<bitPosi;
+ }
+
+ break;
+
+ case 1:
+
+ if (bitPosi < 16 ) {
+ bitPosi = bitPosi * 2;
+ LPC_PINCON->PINMODE2 |= dir<<bitPosi;
+ } else if (bitPosi > 15){
+ bitPosi = bitPosi - 16;
+ bitPosi = bitPosi * 2;
+ LPC_PINCON->PINMODE3 |= dir<<bitPosi;
+ }
+
+ break;
+
+ case 2:
+
+ if (bitPosi < 14 ) {
+ bitPosi = bitPosi * 2;
+ LPC_PINCON->PINMODE4 |= dir<<bitPosi;
+ }
+
+ break;
+
+ case 3:
+
+ if (bitPosi == 25){
+ LPC_PINCON->PINMODE7 |= dir<<18;
+ }else if (bitPosi == 26){
+ LPC_PINCON->PINMODE7 |= dir<<20;
+ }
+
+ break;
+
+ case 4:
+ if (bitPosi == 28){
+ LPC_PINCON->PINMODE9 |= dir<<24;
+ }else if (bitPosi == 29){
+ LPC_PINCON->PINMODE9 |= dir<<26;
+ }
+
+ }
+}
+
+uint32_t GPIOGetValue (uint32_t portNum, uint32_t bitPosi)
+{
+ uint32_t val;
+ LPC_GPIO[portNum]->FIOMASK = ~(1<<bitPosi);
+ val = LPC_GPIO[portNum]->FIOPIN;
+ val = val >> bitPosi;
+ LPC_GPIO[portNum]->FIOMASK = 0x00000000;
+ return val;
+}
+
+void GPIOSetInterrupt ( uint32_t portNum, uint32_t bitPosi, uint32_t dir )
+{
+ // Dir is 0 for falling edge interrupt and 1 for rising edge interrupt
+ if (portNum == 0)
+ {
+ if (dir == 0)
+ {
+ LPC_GPIOINT->IO0IntEnF |= (1<<bitPosi);
+ }
+ else if (dir == 1)
+ {
+ LPC_GPIOINT->IO0IntEnR |= (1<<bitPosi);
+ }
+ }
+ else if (portNum == 2)
+ {
+ if (dir == 0)
+ {
+ LPC_GPIOINT->IO2IntEnF |= (1<<bitPosi);
+ }
+ else if (dir == 1)
+ {
+ LPC_GPIOINT->IO2IntEnR |= (1<<bitPosi);
+ }
+ }
+
+ NVIC_EnableIRQ(EINT3_IRQn);
+}
+
+void GPIOClearInterrupt( void )
+{
+ LPC_GPIOINT->IO0IntClr = 0x7FFF8FFF;
+ LPC_GPIOINT->IO2IntClr = 0x3fff;
+}
+
+uint32_t GPIOCheckInterrupts ( uint32_t portNum, uint32_t dir)
+{
+ // Dir is 0 for falling edge interrupt and 1 for rising edge interrupt
+ if (portNum == 0)
+ {
+ if (dir == 0)
+ {
+ return LPC_GPIOINT->IO0IntStatF;
+ }
+ else if (dir == 1)
+ {
+ return LPC_GPIOINT->IO0IntStatR;
+ }
+ }
+ else if (portNum == 2)
+ {
+ if (dir == 0)
+ {
+ return LPC_GPIOINT->IO0IntStatF;
+ }
+ else if (dir == 1)
+ {
+ return LPC_GPIOINT->IO0IntStatR;
+ }
+ }
+ return FALSE;
+}
diff --git a/firmware/drivers/GPIO.h b/firmware/drivers/GPIO.h
new file mode 100644
index 0000000..9393edc
--- /dev/null
+++ b/firmware/drivers/GPIO.h
@@ -0,0 +1,21 @@
+
+extern void GPIOSetDir( uint32_t portNum, uint32_t bitPosi, uint32_t dir );
+extern void GPIOSetValue( uint32_t portNum, uint32_t bitPosi, uint32_t bitVal );
+extern void GPIOSetPull(uint32_t portNum, uint32_t bitPosi, uint32_t dir);
+extern uint32_t GPIOGetValue (uint32_t portNum, uint32_t bitPosi);
+void GPIOSetInterrupt ( uint32_t portNum, uint32_t bitPosi, uint32_t dir );
+void GPIOClearInterrupt( void );
+uint32_t GPIOCheckInterrupts ( uint32_t portNum, uint32_t dir);
+
+#define NOPULL 0
+#define PULLUP 1
+#define PULLDOWN 2
+
+#define INPUT 0
+#define OUTPUT 1
+
+#define FALLING 0
+#define RISING 1
+
+#define LOW 0
+#define HIGH 1
diff --git a/firmware/drivers/spi.c b/firmware/drivers/spi.c
index 6209a03..fcbb6cc 100644
--- a/firmware/drivers/spi.c
+++ b/firmware/drivers/spi.c
@@ -28,6 +28,7 @@
#include <LPC17xx.h>
+#if 0
#define USE_CMSIS
@@ -100,7 +101,7 @@ void spi_init()
spi_cfg.DataOrder = SPI_DATA_MSB_FIRST;
// Se WM8523 manual page 14. Min clock pulse width 40ns ~= 25MHz
- spi_cfg.ClockRate = 1000;//1000000000; // 1MHz
+ spi_cfg.ClockRate = 10000;//1000000000; // 1MHz
spi = LPC_SPI;
SPI_Init(spi, &spi_cfg);
@@ -118,10 +119,10 @@ void spi_init()
LPC_SC->PCLKSEL0 |= ((clk & 0x3) << PCLK_SPI_BIT); // set bit 16 and 17 in PCLKSEL0
// Make pin selection for SPI.
- // SCK0: P1.20
- // SSEL0: P1.21
- // MOSI0: P1.23
- // MISO0: P1.24
+ // SCK0: P0.15
+ // SSEL0: P0.16
+ // MOSI0: P0.17
+ // MISO0: P0.18
LPC_PINCON->PINSEL0 &= ~(0x3 << SCK0_BIT);
LPC_PINCON->PINSEL0 |= (SCK0_FUNCTION << SCK0_BIT);
@@ -143,7 +144,7 @@ void spi_init()
#endif/*USE_CMSIS*/
// Configure SSEL pin:
- LPC_GPIO1->FIODIR |= 1 << 21; // Set 1.21 in output mode
+ LPC_GPIO0->FIODIR |= 1 << 16; // Set P0.16 in output mode
}
@@ -203,29 +204,29 @@ void spi_read_write(uint8_t *tx_data, uint8_t *rx_data, size_t length)
dst.callback = spi_mark_as_done;
SPI_ClearIntPending(spi);
- LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low
+ LPC_GPIO0->FIOPIN &= ~( 1 << 16 ); // make P0.16 low
spi_done = 0;
SPI_ReadWrite(spi, &dst, SPI_TRANSFER_POLLING);//SPI_TRANSFER_INTERRUPT);
- cli_write(">");
+ // cli_write(">");
while (!(SPI_GetStatus(spi) & SPI_SPSR_SPIF)) { }
//while(!spi_done) {}
- cli_write("<");
+ //cli_write("<");
- LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high
+ LPC_GPIO0->FIOPIN |= 1 << 16; // make P0.16 high
#else/*USE_CMSIS*/
int i = 0;
- cli_write(">>");
+ // cli_write(">>");
- LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low
+ LPC_GPIO0->FIOPIN &= ~( 1 << 16 ); // make P0.16 low
for(; i < length; i++) {
/*
cli_write("w");
- LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low
+ LPC_GPIO0->FIOPIN &= ~( 1 << 16 ); // make P0.16 low
__delay(1 << 23);
*/
@@ -252,13 +253,15 @@ void spi_read_write(uint8_t *tx_data, uint8_t *rx_data, size_t length)
/*
cli_write("r");
- LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high
+ LPC_GPIO0->FIOPIN |= 1 << 16; // make P0.16 high
__delay(1 << 23);
*/
}
- LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high
+ LPC_GPIO0->FIOPIN |= 1 << 16; // make P0.16 high
- cli_write("<<");
+ //cli_write("<<");
#endif/*USE_CMSIS*/
}
+
+#endif/*0*/
diff --git a/firmware/drivers/ssp.c b/firmware/drivers/ssp.c
new file mode 100644
index 0000000..ad2c6fe
--- /dev/null
+++ b/firmware/drivers/ssp.c
@@ -0,0 +1,413 @@
+/****************************************************************************
+ * $Id:: ssp.c 5804 2010-12-04 00:32:12Z usb00423 $
+ * Project: NXP LPC17xx SSP example
+ *
+ * Description:
+ * This file contains SSP code example which include SSP initialization,
+ * SSP interrupt handler, and APIs for SSP access.
+ *
+ ****************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * NXP Semiconductors assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. NXP Semiconductors
+ * reserves the right to make changes in the software without
+ * notification. NXP Semiconductors also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+****************************************************************************/
+#include <LPC17xx.h> /* LPC17xx Peripheral Registers */
+#include "ssp.h"
+
+/* statistics of all the interrupts */
+volatile uint32_t interrupt0RxStat = 0;
+volatile uint32_t interrupt0OverRunStat = 0;
+volatile uint32_t interrupt0RxTimeoutStat = 0;
+volatile uint32_t interrupt1RxStat = 0;
+volatile uint32_t interrupt1OverRunStat = 0;
+volatile uint32_t interrupt1RxTimeoutStat = 0;
+
+/*****************************************************************************
+** Function name: SSP_IRQHandler
+**
+** Descriptions: SSP port is used for SPI communication.
+** SSP interrupt handler
+** The algorithm is, if RXFIFO is at least half full,
+** start receive until it's empty; if TXFIFO is at least
+** half empty, start transmit until it's full.
+** This will maximize the use of both FIFOs and performance.
+**
+** parameters: None
+** Returned value: None
+**
+*****************************************************************************/
+void SSP0_IRQHandler(void)
+{
+ uint32_t regValue;
+
+ regValue = LPC_SSP0->MIS;
+ if ( regValue & SSPMIS_RORMIS ) /* Receive overrun interrupt */
+ {
+ interrupt0OverRunStat++;
+ LPC_SSP0->ICR = SSPICR_RORIC; /* clear interrupt */
+ }
+ if ( regValue & SSPMIS_RTMIS ) /* Receive timeout interrupt */
+ {
+ interrupt0RxTimeoutStat++;
+ LPC_SSP0->ICR = SSPICR_RTIC; /* clear interrupt */
+ }
+
+ /* please be aware that, in main and ISR, CurrentRxIndex and CurrentTxIndex
+ are shared as global variables. It may create some race condition that main
+ and ISR manipulate these variables at the same time. SSPSR_BSY checking (polling)
+ in both main and ISR could prevent this kind of race condition */
+ if ( regValue & SSPMIS_RXMIS ) /* Rx at least half full */
+ {
+ interrupt0RxStat++; /* receive until it's empty */
+ }
+ return;
+}
+
+/*****************************************************************************
+** Function name: SSP_IRQHandler
+**
+** Descriptions: SSP port is used for SPI communication.
+** SSP interrupt handler
+** The algorithm is, if RXFIFO is at least half full,
+** start receive until it's empty; if TXFIFO is at least
+** half empty, start transmit until it's full.
+** This will maximize the use of both FIFOs and performance.
+**
+** parameters: None
+** Returned value: None
+**
+*****************************************************************************/
+void SSP1_IRQHandler(void)
+{
+ uint32_t regValue;
+
+ regValue = LPC_SSP1->MIS;
+ if ( regValue & SSPMIS_RORMIS ) /* Receive overrun interrupt */
+ {
+ interrupt1OverRunStat++;
+ LPC_SSP1->ICR = SSPICR_RORIC; /* clear interrupt */
+ }
+ if ( regValue & SSPMIS_RTMIS ) /* Receive timeout interrupt */
+ {
+ interrupt1RxTimeoutStat++;
+ LPC_SSP1->ICR = SSPICR_RTIC; /* clear interrupt */
+ }
+
+ /* please be aware that, in main and ISR, CurrentRxIndex and CurrentTxIndex
+ are shared as global variables. It may create some race condition that main
+ and ISR manipulate these variables at the same time. SSPSR_BSY checking (polling)
+ in both main and ISR could prevent this kind of race condition */
+ if ( regValue & SSPMIS_RXMIS ) /* Rx at least half full */
+ {
+ interrupt1RxStat++; /* receive until it's empty */
+ }
+ return;
+}
+
+/*****************************************************************************
+** Function name: SSP0_SSELToggle
+**
+** Descriptions: SSP0 CS manual set
+**
+** parameters: port num, toggle(1 is high, 0 is low)
+** Returned value: None
+**
+*****************************************************************************/
+void SSP_SSELToggle( uint32_t portnum, uint32_t toggle )
+{
+ if ( portnum == 0 )
+ {
+ if ( !toggle )
+ LPC_GPIO0->FIOCLR |= (0x1<<16);
+ else
+ LPC_GPIO0->FIOSET |= (0x1<<16);
+ }
+ else if ( portnum == 1 )
+ {
+ if ( !toggle )
+ LPC_GPIO0->FIOCLR |= (0x1<<6);
+ else
+ LPC_GPIO0->FIOSET |= (0x1<<6);
+ }
+ return;
+}
+
+// Bent code:
+// SPI power bit in PCONP register (see table 46)
+#define PCSPI_BIT 8
+
+// SPI clock bits (16 and 17) in PCLKSEL0 register (see table 40)
+#define PCLK_SPI_BIT 16
+
+typedef enum {
+ CCLK_4 = 0x0, // 00: PCLK_peripheral = CCLK/4
+ CCLK_1 = 0x1, // 01: PCLK_peripheral = CCLK
+ CCLK_2 = 0x2, // 10: PCLK_peripheral = CCLK/2
+ CCLK_8 = 0x3, // 11: PCLK_peripheral = CCLK/8
+} ClockDevisor;
+
+/*****************************************************************************
+** Function name: SSPInit
+**
+** Descriptions: SSP port initialization routine
+**
+** parameters: None
+** Returned value: None
+**
+*****************************************************************************/
+void SSP0Init( void )
+{
+ uint8_t i, Dummy=Dummy;
+
+ /* Enable AHB clock to the SSP0. */
+ //LPC_SC->PCONP |= (0x1<<21);
+
+ /* Further divider is needed on SSP0 clock. Using default divided by 4 */
+ //LPC_SC->PCLKSEL1 &= ~(0x3<<10);
+
+ //Bent code:
+ // Power up the SPI bus.
+ // Remark: On reset, the SPI is enabled (PCSPI = 1).
+ LPC_SC->PCONP |= (1 << PCSPI_BIT); // set bit 8 in PCONP (PCSPI bit)
+
+ ClockDevisor clk = CCLK_8;
+ LPC_SC->PCLKSEL0 &= ~(0x3 << PCLK_SPI_BIT);
+ LPC_SC->PCLKSEL0 |= ((clk & 0x3) << PCLK_SPI_BIT); // set bit 16 and 17 in PCLKSEL0
+
+
+ /* P0.15~0.18 as SSP0 */
+ LPC_PINCON->PINSEL0 &= ~(0x3UL<<30);
+ LPC_PINCON->PINSEL0 |= (0x2UL<<30);
+ LPC_PINCON->PINSEL1 &= ~((0x3<<0)|(0x3<<2)|(0x3<<4));
+ LPC_PINCON->PINSEL1 |= ((0x2<<0)|(0x2<<2)|(0x2<<4));
+
+#if !USE_CS
+ LPC_PINCON->PINSEL1 &= ~(0x3<<0);
+ LPC_GPIO0->FIODIR |= (0x1<<16); /* P0.16 defined as GPIO and Outputs */
+#endif
+
+ /* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15 */
+ LPC_SSP0->CR0 = 0x0707;
+
+ /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */
+ LPC_SSP0->CPSR = 0x2;
+
+ for ( i = 0; i < FIFOSIZE; i++ )
+ {
+ Dummy = LPC_SSP0->DR; /* clear the RxFIFO */
+ }
+
+ /* Enable the SSP Interrupt */
+ NVIC_EnableIRQ(SSP0_IRQn);
+
+ /* Device select as master, SSP Enabled */
+#if LOOPBACK_MODE
+ LPC_SSP0->CR1 = SSPCR1_LBM | SSPCR1_SSE;
+#else
+#if SSP_SLAVE
+ /* Slave mode */
+ if ( LPC_SSP0->CR1 & SSPCR1_SSE )
+ {
+ /* The slave bit can't be set until SSE bit is zero. */
+ LPC_SSP0->CR1 &= ~SSPCR1_SSE;
+ }
+ LPC_SSP0->CR1 = SSPCR1_MS; /* Enable slave bit first */
+ LPC_SSP0->CR1 |= SSPCR1_SSE; /* Enable SSP */
+#else
+ /* Master mode */
+ LPC_SSP0->CR1 = SSPCR1_SSE;
+#endif
+#endif
+ /* Set SSPINMS registers to enable interrupts */
+ /* enable all error related interrupts */
+ LPC_SSP0->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM;
+ return;
+}
+
+/*****************************************************************************
+** Function name: SSPInit
+**
+** Descriptions: SSP port initialization routine
+**
+** parameters: None
+** Returned value: None
+**
+*****************************************************************************/
+void SSP1Init( void )
+{
+ uint8_t i, Dummy=Dummy;
+
+ /* Enable AHB clock to the SSP1. */
+ LPC_SC->PCONP |= (0x1<<10);
+
+ /* Further divider is needed on SSP1 clock. Using default divided by 4 */
+ LPC_SC->PCLKSEL0 &= ~(0x3<<20);
+
+ /* P0.6~0.9 as SSP1 */
+ LPC_PINCON->PINSEL0 &= ~((0x3<<12)|(0x3<<14)|(0x3<<16)|(0x3<<18));
+ LPC_PINCON->PINSEL0 |= ((0x2<<12)|(0x2<<14)|(0x2<<16)|(0x2<<18));
+
+#if !USE_CS
+ LPC_PINCON->PINSEL0 &= ~(0x3<<12);
+ LPC_GPIO0->FIODIR |= (0x1<<6); /* P0.6 defined as GPIO and Outputs */
+#endif
+
+ /* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15 */
+ LPC_SSP1->CR0 = 0x0707;
+
+ /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */
+ LPC_SSP1->CPSR = 0x2;
+
+ for ( i = 0; i < FIFOSIZE; i++ )
+ {
+ Dummy = LPC_SSP1->DR; /* clear the RxFIFO */
+ }
+
+ /* Enable the SSP Interrupt */
+ NVIC_EnableIRQ(SSP1_IRQn);
+
+ /* Device select as master, SSP Enabled */
+#if LOOPBACK_MODE
+ LPC_SSP1->CR1 = SSPCR1_LBM | SSPCR1_SSE;
+#else
+#if SSP_SLAVE
+ /* Slave mode */
+ if ( LPC_SSP1->CR1 & SSPCR1_SSE )
+ {
+ /* The slave bit can't be set until SSE bit is zero. */
+ LPC_SSP1->CR1 &= ~SSPCR1_SSE;
+ }
+ LPC_SSP1->CR1 = SSPCR1_MS; /* Enable slave bit first */
+ LPC_SSP1->CR1 |= SSPCR1_SSE; /* Enable SSP */
+#else
+ /* Master mode */
+ LPC_SSP1->CR1 = SSPCR1_SSE;
+#endif
+#endif
+ /* Set SSPINMS registers to enable interrupts */
+ /* enable all error related interrupts */
+ LPC_SSP1->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM;
+ return;
+}
+
+/*****************************************************************************
+** Function name: SSPSend
+**
+** Descriptions: Send a block of data to the SSP port, the
+** first parameter is the buffer pointer, the 2nd
+** parameter is the block length.
+**
+** parameters: buffer pointer, and the block length
+** Returned value: None
+**
+*****************************************************************************/
+void SSPSend( uint32_t portnum, uint8_t *buf, uint32_t Length )
+{
+ uint32_t i;
+ uint8_t Dummy = Dummy;
+
+ for ( i = 0; i < Length; i++ )
+ {
+ if ( portnum == 0 )
+ {
+ /* Move on only if NOT busy and TX FIFO not full. */
+ while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
+ LPC_SSP0->DR = *buf;
+ buf++;
+#if !LOOPBACK_MODE
+ while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
+ /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
+ on MISO. Otherwise, when SSP0Receive() is called, previous data byte
+ is left in the FIFO. */
+ Dummy = LPC_SSP0->DR;
+#else
+ /* Wait until the Busy bit is cleared. */
+ while ( LPC_SSP0->SR & SSPSR_BSY );
+#endif
+ }
+ else if ( portnum == 1 )
+ {
+ /* Move on only if NOT busy and TX FIFO not full. */
+ while ( (LPC_SSP1->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
+ LPC_SSP1->DR = *buf;
+ buf++;
+#if !LOOPBACK_MODE
+ while ( (LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
+ /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
+ on MISO. Otherwise, when SSP0Receive() is called, previous data byte
+ is left in the FIFO. */
+ Dummy = LPC_SSP1->DR;
+#else
+ /* Wait until the Busy bit is cleared. */
+ while ( LPC_SSP1->SR & SSPSR_BSY );
+#endif
+ }
+ }
+ return;
+}
+
+/*****************************************************************************
+** Function name: SSPReceive
+** Descriptions: the module will receive a block of data from
+** the SSP, the 2nd parameter is the block
+** length.
+** parameters: buffer pointer, and block length
+** Returned value: None
+**
+*****************************************************************************/
+void SSPReceive( uint32_t portnum, uint8_t *buf, uint32_t Length )
+{
+ uint32_t i;
+
+ for ( i = 0; i < Length; i++ )
+ {
+ /* As long as Receive FIFO is not empty, I can always receive. */
+ /* If it's a loopback test, clock is shared for both TX and RX,
+ no need to write dummy byte to get clock to get the data */
+ /* if it's a peer-to-peer communication, SSPDR needs to be written
+ before a read can take place. */
+ if ( portnum == 0 )
+ {
+#if !LOOPBACK_MODE
+#if SSP_SLAVE
+ while ( !(LPC_SSP0->SR & SSPSR_RNE) );
+#else
+ LPC_SSP0->DR = 0xFF;
+ /* Wait until the Busy bit is cleared */
+ while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
+#endif
+#else
+ while ( !(LPC_SSP0->SR & SSPSR_RNE) );
+#endif
+ *buf++ = LPC_SSP0->DR;
+ }
+ else if ( portnum == 1 )
+ {
+#if !LOOPBACK_MODE
+#if SSP_SLAVE
+ while ( !(LPC_SSP1->SR & SSPSR_RNE) );
+#else
+ LPC_SSP1->DR = 0xFF;
+ /* Wait until the Busy bit is cleared */
+ while ( (LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE );
+#endif
+#else
+ while ( !(LPC_SSP1->SR & SSPSR_RNE) );
+#endif
+ *buf++ = LPC_SSP1->DR;
+ }
+ }
+ return;
+}
+
+/******************************************************************************
+** End Of File
+******************************************************************************/
+
diff --git a/firmware/drivers/ssp.h b/firmware/drivers/ssp.h
new file mode 100644
index 0000000..c543422
--- /dev/null
+++ b/firmware/drivers/ssp.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * $Id:: ssp.h 5741 2010-11-30 23:13:47Z usb00423 $
+ * Project: NXP LPC17xx SSP example
+ *
+ * Description:
+ * This file contains SSP code header definition.
+ *
+ ****************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * NXP Semiconductors assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. NXP Semiconductors
+ * reserves the right to make changes in the software without
+ * notification. NXP Semiconductors also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+****************************************************************************/
+#ifndef __SSP_H__
+#define __SSP_H__
+
+/* There are there modes in SSP: loopback, master or slave. */
+/* Here are the combination of all the tests.
+(1) LOOPBACK test: LOOPBACK_MODE=1, TX_RX_ONLY=0, USE_CS=1;
+(2) Serial EEPROM test: LOOPBACK_MODE=0, TX_RX_ONLY=0, USE_CS=0; (default)
+(3) TX(Master) Only: LOOPBACK_MODE=0, SSP_SLAVE=0, TX_RX_ONLY=1, USE_CS=1;
+(4) RX(Slave) Only: LOOPBACK_MODE=0, SSP_SLAVE=1, TX_RX_ONLY=0, USE_CS=1 */
+
+#define LOOPBACK_MODE 0 /* 1 is loopback, 0 is normal operation. */
+#define SSP_SLAVE 0 /* 1 is SLAVE mode, 0 is master mode */
+#define TX_RX_ONLY 0 /* 1 is TX or RX only depending on SSP_SLAVE
+ flag, 0 is either loopback mode or communicate
+ with a serial EEPROM. */
+
+/* if USE_CS is zero, set SSEL as GPIO that you have total control of the sequence */
+/* When test serial SEEPROM(LOOPBACK_MODE=0, TX_RX_ONLY=0), set USE_CS to 0. */
+/* When LOOPBACK_MODE=1 or TX_RX_ONLY=1, set USE_CS to 1. */
+
+#define USE_CS 0
+
+/* SPI read and write buffer size */
+#define SSP_BUFSIZE 16
+#define FIFOSIZE 8
+
+#define DELAY_COUNT 10
+#define MAX_TIMEOUT 0xFF
+
+/* Port0.2 is the SSP select pin */
+#define SSP0_SEL (1 << 2)
+
+/* SSP Status register */
+#define SSPSR_TFE (1 << 0)
+#define SSPSR_TNF (1 << 1)
+#define SSPSR_RNE (1 << 2)
+#define SSPSR_RFF (1 << 3)
+#define SSPSR_BSY (1 << 4)
+
+/* SSP CR0 register */
+#define SSPCR0_DSS (1 << 0)
+#define SSPCR0_FRF (1 << 4)
+#define SSPCR0_SPO (1 << 6)
+#define SSPCR0_SPH (1 << 7)
+#define SSPCR0_SCR (1 << 8)
+
+/* SSP CR1 register */
+#define SSPCR1_LBM (1 << 0)
+#define SSPCR1_SSE (1 << 1)
+#define SSPCR1_MS (1 << 2)
+#define SSPCR1_SOD (1 << 3)
+
+/* SSP Interrupt Mask Set/Clear register */
+#define SSPIMSC_RORIM (1 << 0)
+#define SSPIMSC_RTIM (1 << 1)
+#define SSPIMSC_RXIM (1 << 2)
+#define SSPIMSC_TXIM (1 << 3)
+
+/* SSP0 Interrupt Status register */
+#define SSPRIS_RORRIS (1 << 0)
+#define SSPRIS_RTRIS (1 << 1)
+#define SSPRIS_RXRIS (1 << 2)
+#define SSPRIS_TXRIS (1 << 3)
+
+/* SSP0 Masked Interrupt register */
+#define SSPMIS_RORMIS (1 << 0)
+#define SSPMIS_RTMIS (1 << 1)
+#define SSPMIS_RXMIS (1 << 2)
+#define SSPMIS_TXMIS (1 << 3)
+
+/* SSP0 Interrupt clear register */
+#define SSPICR_RORIC (1 << 0)
+#define SSPICR_RTIC (1 << 1)
+
+/* ATMEL SEEPROM command set */
+#define WREN 0x06 /* MSB A8 is set to 0, simplifying test */
+#define WRDI 0x04
+#define RDSR 0x05
+#define WRSR 0x01
+#define READ 0x03
+#define WRITE 0x02
+
+/* RDSR status bit definition */
+#define RDSR_RDY 0x01
+#define RDSR_WEN 0x02
+
+/* If RX_INTERRUPT is enabled, the SSP RX will be handled in the ISR
+SSPReceive() will not be needed. */
+extern void SSP0_IRQHandler (void);
+extern void SSP1_IRQHandler (void);
+extern void SSP_SSELToggle( uint32_t portnum, uint32_t toggle );
+extern void SSP0Init( void );
+extern void SSP1Init( void );
+extern void SSP2Init( void );
+extern void SSPSend( uint32_t portnum, uint8_t *Buf, uint32_t Length );
+extern void SSPReceive( uint32_t portnum, uint8_t *buf, uint32_t Length );
+
+#endif /* __SSP_H__ */
+/*****************************************************************************
+** End Of File
+******************************************************************************/
+
diff --git a/firmware/drivers/timer.c b/firmware/drivers/timer.c
new file mode 100644
index 0000000..ed9680b
--- /dev/null
+++ b/firmware/drivers/timer.c
@@ -0,0 +1,572 @@
+/****************************************************************************
+ * $Id:: timer.c 5823 2010-12-07 19:01:00Z usb00423 $
+ * Project: NXP LPC17xx Timer for PWM example
+ *
+ * Description:
+ * This file contains timer code example which include timer
+ * initialization, timer interrupt handler, and APIs for timer access.
+ *
+ ****************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * NXP Semiconductors assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. NXP Semiconductors
+ * reserves the right to make changes in the software without
+ * notification. NXP Semiconductors also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+****************************************************************************/
+#include <LPC17xx.h>
+
+//#include "lpc_types.h"
+#define FALSE 0
+#define TRUE 1
+
+#include "timer.h"
+
+volatile uint32_t timer0_m0_counter = 0;
+volatile uint32_t timer1_m0_counter = 0;
+volatile uint32_t timer2_m0_counter = 0;
+volatile uint32_t timer3_m0_counter = 0;
+volatile uint32_t timer0_m1_counter = 0;
+volatile uint32_t timer1_m1_counter = 0;
+volatile uint32_t timer2_m1_counter = 0;
+volatile uint32_t timer3_m1_counter = 0;
+
+volatile uint32_t timer0_capture0 = 0;
+volatile uint32_t timer1_capture0 = 0;
+volatile uint32_t timer2_capture0 = 0;
+volatile uint32_t timer3_capture0 = 0;
+volatile uint32_t timer0_capture1 = 0;
+volatile uint32_t timer1_capture1 = 0;
+volatile uint32_t timer2_capture1 = 0;
+volatile uint32_t timer3_capture1 = 0;
+
+/*****************************************************************************
+** Function name: delayMs
+**
+** Descriptions: Start the timer delay in milo seconds
+** until elapsed
+**
+** parameters: timer number, Delay value in milo second
+**
+** Returned value: None
+**
+*****************************************************************************/
+void delayMs(uint8_t timer_num, uint32_t delayInMs)
+{
+ if ( timer_num == 0 )
+ {
+ LPC_TIM0->TCR = 0x02; /* reset timer */
+ LPC_TIM0->PR = 0x00; /* set prescaler to zero */
+ LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time
+ LPC_TIM0->IR = 0xff; /* reset all interrrupts */
+ LPC_TIM0->MCR = 0x04; /* stop timer on match */
+ LPC_TIM0->TCR = 0x01; /* start timer */
+
+ /* wait until delay time has elapsed */
+ while (LPC_TIM0->TCR & 0x01);
+
+ }
+ else if ( timer_num == 1 )
+ {
+ LPC_TIM1->TCR = 0x02; /* reset timer */
+ LPC_TIM1->PR = 0x00; /* set prescaler to zero */
+ LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time
+ LPC_TIM1->IR = 0xff; /* reset all interrrupts */
+ LPC_TIM1->MCR = 0x04; /* stop timer on match */
+ LPC_TIM1->TCR = 0x01; /* start timer */
+
+ /* wait until delay time has elapsed */
+ while (LPC_TIM1->TCR & 0x01);
+ }
+
+ else if ( timer_num == 2 )
+ {
+ LPC_TIM2->TCR = 0x02; /* reset timer */
+ LPC_TIM2->PR = 0x00; /* set prescaler to zero */
+ LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time
+ LPC_TIM2->IR = 0xff; /* reset all interrrupts */
+ LPC_TIM2->MCR = 0x04; /* stop timer on match */
+ LPC_TIM2->TCR = 0x01; /* start timer */
+
+ /* wait until delay time has elapsed */
+ while (LPC_TIM2->TCR & 0x01);
+ }
+
+ else if ( timer_num == 3 )
+ {
+ LPC_TIM3->TCR = 0x02; /* reset timer */
+ LPC_TIM3->PR = 0x00; /* set prescaler to zero */
+ LPC_TIM0->MR0 = (SystemCoreClock / 4) / (1000/delayInMs); //enter delay time
+ LPC_TIM3->IR = 0xff; /* reset all interrrupts */
+ LPC_TIM3->MCR = 0x04; /* stop timer on match */
+ LPC_TIM3->TCR = 0x01; /* start timer */
+
+ /* wait until delay time has elapsed */
+ while (LPC_TIM3->TCR & 0x01);
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: Timer0_IRQHandler
+**
+** Descriptions: Timer/Counter 0 interrupt handler
+**
+** parameters: None
+** Returned value: None
+**
+******************************************************************************/
+void TIMER0_interrupt (void)
+{
+ if ( LPC_TIM0->IR & (0x1<<0) )
+ {
+ LPC_TIM0->IR = 0x1<<0; /* clear interrupt flag */
+ timer0_m0_counter++;
+ }
+ if ( LPC_TIM0->IR & (0x1<<1) )
+ {
+ LPC_TIM0->IR = 0x1<<1; /* clear interrupt flag */
+ timer0_m1_counter++;
+ }
+ if ( LPC_TIM0->IR & (0x1<<4) )
+ {
+ LPC_TIM0->IR = 0x1<<4; /* clear interrupt flag */
+ timer0_capture0++;
+ }
+ if ( LPC_TIM0->IR & (0x1<<5) )
+ {
+ LPC_TIM0->IR = 0x1<<5; /* clear interrupt flag */
+ timer0_capture1++;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: Timer1_IRQHandler
+**
+** Descriptions: Timer/Counter 1 interrupt handler
+**
+** parameters: None
+** Returned value: None
+**
+******************************************************************************/
+void TIMER1_interrupt (void)
+{
+ if ( LPC_TIM1->IR & (0x1<<0) )
+ {
+ LPC_TIM1->IR = 0x1<<0; /* clear interrupt flag */
+ timer1_m0_counter++;
+ }
+ if ( LPC_TIM1->IR & (0x1<<1) )
+ {
+ LPC_TIM1->IR = 0x1<<1; /* clear interrupt flag */
+ timer1_m1_counter++;
+ }
+ if ( LPC_TIM1->IR & (0x1<<4) )
+ {
+ LPC_TIM1->IR = 0x1<<4; /* clear interrupt flag */
+ timer1_capture0++;
+ }
+ if ( LPC_TIM1->IR & (0x1<<5) )
+ {
+ LPC_TIM1->IR = 0x1<<5; /* clear interrupt flag */
+ timer1_capture1++;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: Timer2_IRQHandler
+**
+** Descriptions: Timer/Counter 2 interrupt handler
+**
+** parameters: None
+** Returned value: None
+**
+******************************************************************************/
+void TIMER2_interrupt (void)
+{
+ if ( LPC_TIM2->IR & (0x1<<0) )
+ {
+ LPC_TIM2->IR = 0x1<<0; /* clear interrupt flag */
+ timer2_m0_counter++;
+ }
+ if ( LPC_TIM2->IR & (0x1<<1) )
+ {
+ LPC_TIM2->IR = 0x1<<1; /* clear interrupt flag */
+ timer2_m1_counter++;
+ }
+ if ( LPC_TIM2->IR & (0x1<<4) )
+ {
+ LPC_TIM2->IR = 0x1<<4; /* clear interrupt flag */
+ timer2_capture0++;
+ }
+ if ( LPC_TIM2->IR & (0x1<<5) )
+ {
+ LPC_TIM2->IR = 0x1<<5; /* clear interrupt flag */
+ timer2_capture1++;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: Timer3_IRQHandler
+**
+** Descriptions: Timer/Counter 3 interrupt handler
+**
+** parameters: None
+** Returned value: None
+**
+******************************************************************************/
+void TIMER3_interrupt (void)
+{
+ if ( LPC_TIM3->IR & (0x1<<0) )
+ {
+ LPC_TIM3->IR = 0x1<<0; /* clear interrupt flag */
+ timer3_m0_counter++;
+ }
+ if ( LPC_TIM3->IR & (0x1<<1) )
+ {
+ LPC_TIM3->IR = 0x1<<1; /* clear interrupt flag */
+ timer3_m1_counter++;
+ }
+ if ( LPC_TIM3->IR & (0x1<<4) )
+ {
+ LPC_TIM3->IR = 0x1<<4; /* clear interrupt flag */
+ timer3_capture0++;
+ }
+ if ( LPC_TIM3->IR & (0x1<<5) )
+ {
+ LPC_TIM3->IR = 0x1<<5; /* clear interrupt flag */
+ timer3_capture1++;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: enable_timer
+**
+** Descriptions: Enable timer
+**
+** parameters: timer number: 0 or 1 or 2 or 3
+** Returned value: None
+**
+******************************************************************************/
+void enable_timer( uint8_t timer_num )
+{
+ if ( timer_num == 0 )
+ {
+ LPC_TIM0->TCR = 1;
+ }
+ else if ( timer_num == 1 )
+ {
+ LPC_TIM1->TCR = 1;
+ }
+ else if ( timer_num == 2 )
+ {
+ LPC_TIM2->TCR = 1;
+ }
+ else if ( timer_num == 3 )
+ {
+ LPC_TIM3->TCR = 1;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: disable_timer
+**
+** Descriptions: Disable timer
+**
+** parameters: timer number: 0 or 1 oe 2 or 3
+** Returned value: None
+**
+******************************************************************************/
+void disable_timer( uint8_t timer_num )
+{
+ if ( timer_num == 0 )
+ {
+ LPC_TIM0->TCR = 0;
+ }
+ else if ( timer_num == 1 )
+ {
+ LPC_TIM1->TCR = 0;
+ }
+ else if ( timer_num == 2 )
+ {
+ LPC_TIM2->TCR = 0;
+ }
+ else if ( timer_num == 3 )
+ {
+ LPC_TIM2->TCR = 0;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: reset_timer
+**
+** Descriptions: Reset timer
+**
+** parameters: timer number: 0 or 1 or 2 or 3
+** Returned value: None
+**
+******************************************************************************/
+void reset_timer( uint8_t timer_num )
+{
+ uint32_t regVal;
+
+ if ( timer_num == 0 )
+ {
+ regVal = LPC_TIM0->TCR;
+ regVal |= 0x02;
+ LPC_TIM0->TCR = regVal;
+ }
+ else if ( timer_num == 1 )
+ {
+ regVal = LPC_TIM1->TCR;
+ regVal |= 0x02;
+ LPC_TIM1->TCR = regVal;
+ }
+ else if ( timer_num == 2 )
+ {
+ regVal = LPC_TIM2->TCR;
+ regVal |= 0x02;
+ LPC_TIM2->TCR = regVal;
+ }
+ else if ( timer_num == 3 )
+ {
+ regVal = LPC_TIM3->TCR;
+ regVal |= 0x02;
+ LPC_TIM3->TCR = regVal;
+ }
+ return;
+}
+
+/******************************************************************************
+** Function name: init_timer
+**
+** Descriptions: Initialize timer, set timer interval, reset timer,
+** install timer interrupt handler
+**
+** parameters: timer number and timer interval
+** Returned value: true or false, if the interrupt handler can't be
+** installed, return false.
+**
+******************************************************************************/
+uint32_t TimerInit( uint8_t timer_num, uint32_t TimerInterval )
+{
+ uint32_t pclkdiv, pclk;
+ (void)pclk;
+
+ if ( timer_num == 0 )
+ {
+ timer0_m0_counter = 0;
+ timer0_m1_counter = 0;
+ timer0_capture0 = 0;
+ timer0_capture1 = 0;
+ LPC_SC->PCONP |= (0x01<<1);
+#if TIMER_MATCH
+ LPC_PINCON->PINSEL3 &= ~((0x3<<24)|(0x3<<26));
+ LPC_PINCON->PINSEL3 |= ((0x3<<24)|(0x3<<26));
+#else
+ LPC_PINCON->PINSEL3 &= ~((0x3<<20)|(0x3<<22));
+ LPC_PINCON->PINSEL3 |= ((0x3<<20)|(0x3<<22));
+#endif
+ LPC_TIM0->IR = 0x0F; /* Clear MATx interrupt include DMA request */
+
+ /* By default, the PCLKSELx value is zero, thus, the PCLK for
+ all the peripherals is 1/4 of the SystemCoreClock. */
+ /* Bit 2~3 is for TIMER0 */
+ pclkdiv = (LPC_SC->PCLKSEL0 >> 2) & 0x03;
+ switch ( pclkdiv )
+ {
+ case 0x00:
+ default:
+ pclk = SystemCoreClock/4;
+ break;
+ case 0x01:
+ pclk = SystemCoreClock;
+ break;
+ case 0x02:
+ pclk = SystemCoreClock/2;
+ break;
+ case 0x03:
+ pclk = SystemCoreClock/8;
+ break;
+ }
+ LPC_TIM0->PR = 0;
+
+ LPC_TIM0->MR0 = TimerInterval/4;
+ LPC_TIM0->MR1 = TimerInterval/4;
+#if TIMER_MATCH
+ LPC_TIM0->EMR &= ~(0xFF<<4);
+ LPC_TIM0->EMR |= ((0x3<<4)|(0x3<<6));
+#else
+ /* Capture 0 and 1 on rising edge, interrupt enable. */
+ LPC_TIM0->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5);
+#endif
+ LPC_TIM0->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */
+ NVIC_EnableIRQ(TIMER0_IRQn);
+ return (TRUE);
+ }
+ else if ( timer_num == 1 )
+ {
+ timer1_m0_counter = 0;
+ timer1_m1_counter = 0;
+ timer1_capture0 = 0;
+ timer1_capture1 = 0;
+ LPC_SC->PCONP |= (0x1<<2);
+#if TIMER_MATCH
+ LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18));
+ LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18));
+#else
+ LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6));
+ LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6));
+#endif
+ LPC_TIM1->IR = 0x0F; /* Clear MATx interrupt include DMA request */
+ /* By default, the PCLKSELx value is zero, thus, the PCLK for
+ all the peripherals is 1/4 of the SystemCoreClock. */
+ /* Bit 4~5 is for TIMER0 */
+ pclkdiv = (LPC_SC->PCLKSEL0 >> 4) & 0x03;
+ switch ( pclkdiv )
+ {
+ case 0x00:
+ default:
+ pclk = SystemCoreClock/4;
+ break;
+ case 0x01:
+ pclk = SystemCoreClock;
+ break;
+ case 0x02:
+ pclk = SystemCoreClock/2;
+ break;
+ case 0x03:
+ pclk = SystemCoreClock/8;
+ break;
+ }
+ LPC_TIM1->PR = 0;
+ LPC_TIM1->MR0 = TimerInterval/4;
+ LPC_TIM1->MR1 = TimerInterval/4;
+#if TIMER_MATCH
+ LPC_TIM1->EMR &= ~(0xFF<<4);
+ LPC_TIM1->EMR |= ((0x3<<4)|(0x3<<6));
+#else
+ /* Capture 0/1 on rising edge, interrupt enable. */
+ LPC_TIM1->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5);
+#endif
+ LPC_TIM1->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */
+ NVIC_EnableIRQ(TIMER1_IRQn);
+ return (TRUE);
+ }
+
+ else if ( timer_num == 2 )
+ {
+ timer2_m0_counter = 0;
+ timer2_m1_counter = 0;
+ timer2_capture0 = 0;
+ timer2_capture1 = 0;
+ LPC_SC->PCONP |= (0x1<<22);
+ #if TIMER_MATCH
+ LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18));
+ LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18));
+ #else
+ LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6));
+ LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6));
+ #endif
+ LPC_TIM2->IR = 0x0F; /* Clear MATx interrupt include DMA request */
+ /* By default, the PCLKSELx value is zero, thus, the PCLK for
+ all the peripherals is 1/4 of the SystemCoreClock. */
+ /* Bit 12~13 is for TIMER2 */
+ pclkdiv = (LPC_SC->PCLKSEL1 >> 12) & 0x03;
+ switch ( pclkdiv )
+ {
+ case 0x00:
+ default:
+ pclk = SystemCoreClock/4;
+ break;
+ case 0x01:
+ pclk = SystemCoreClock;
+ break;
+ case 0x02:
+ pclk = SystemCoreClock/2;
+ break;
+ case 0x03:
+ pclk = SystemCoreClock/8;
+ break;
+ }
+ LPC_TIM2->PR = 0;
+ LPC_TIM2->MR0 = TimerInterval/4;
+ LPC_TIM2->MR1 = TimerInterval/4;
+ #if TIMER_MATCH
+ LPC_TIM2->EMR &= ~(0xFF<<4);
+ LPC_TIM2->EMR |= ((0x3<<4)|(0x3<<6));
+ #else
+ /* Capture 0/1 on rising edge, interrupt enable. */
+ LPC_TIM2->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5);
+ #endif
+ LPC_TIM2->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */
+ NVIC_EnableIRQ(TIMER2_IRQn);
+ return (TRUE);
+ }
+
+ else if ( timer_num == 3 )
+ {
+ timer3_m0_counter = 0;
+ timer3_m1_counter = 0;
+ timer3_capture0 = 0;
+ timer3_capture1 = 0;
+ LPC_SC->PCONP |= (0x1<<23);
+ #if TIMER_MATCH
+ LPC_PINCON->PINSEL3 &= ~((0x3<<12)|(0x3<<18));
+ LPC_PINCON->PINSEL3 |= ((0x3<<12)|(0x3<<18));
+ #else
+ LPC_PINCON->PINSEL3 &= ~((0x3<<4)|(0x3<<6));
+ LPC_PINCON->PINSEL3 |= ((0x3<<4)|(0x3<<6));
+ #endif
+ LPC_TIM3->IR = 0x0F; /* Clear MATx interrupt include DMA request */
+ /* By default, the PCLKSELx value is zero, thus, the PCLK for
+ all the peripherals is 1/4 of the SystemCoreClock. */
+ /* Bit 14~15 is for TIMER3 */
+ pclkdiv = (LPC_SC->PCLKSEL1 >> 14) & 0x03;
+ switch ( pclkdiv )
+ {
+ case 0x00:
+ default:
+ pclk = SystemCoreClock/4;
+ break;
+ case 0x01:
+ pclk = SystemCoreClock;
+ break;
+ case 0x02:
+ pclk = SystemCoreClock/2;
+ break;
+ case 0x03:
+ pclk = SystemCoreClock/8;
+ break;
+ }
+ LPC_TIM3->PR = 0;
+ LPC_TIM3->MR0 = TimerInterval/4;
+ LPC_TIM3->MR1 = TimerInterval/4;
+ #if TIMER_MATCH
+ LPC_TIM3->EMR &= ~(0xFF<<4);
+ LPC_TIM3->EMR |= ((0x3<<4)|(0x3<<6));
+ #else
+ /* Capture 0/1 on rising edge, interrupt enable. */
+ LPC_TIM3->CCR = (0x1<<0)|(0x1<<2)|(0x1<<3)|(0x1<<5);
+ #endif
+ LPC_TIM3->MCR = (0x3<<0)|(0x3<<3); /* Interrupt and Reset on MR0 and MR1 */
+ NVIC_EnableIRQ(TIMER3_IRQn);
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/******************************************************************************
+** End Of File
+******************************************************************************/
diff --git a/firmware/drivers/timer.h b/firmware/drivers/timer.h
new file mode 100644
index 0000000..1f16976
--- /dev/null
+++ b/firmware/drivers/timer.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+ * $Id:: timer.h 5823 2010-12-07 19:01:00Z usb00423 $
+ * Project: NXP LPC17xx Timer example
+ *
+ * Description:
+ * This file contains Timer code header definition.
+ *
+ ****************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * NXP Semiconductors assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. NXP Semiconductors
+ * reserves the right to make changes in the software without
+ * notification. NXP Semiconductors also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+****************************************************************************/
+#ifndef __TIMER_H
+#define __TIMER_H
+
+/* The test is either MAT_OUT or CAP_IN. Default is MAT_OUT. */
+/* If running DMA test, External match is not needed to trigger DMA, but still
+set timer as MATx instead of CAPx. */
+#define TIMER_MATCH 1
+
+/* TIME_INTERVALmS is a value to load the timer match register with
+ to get a 1 mS delay */
+#define TIME_INTERVALmS 1000
+
+#define TIME_INTERVAL (9000000/100 - 1)
+
+extern void delayMs(uint8_t timer_num, uint32_t delayInMs);
+extern uint32_t TimerInit( uint8_t timer_num, uint32_t timerInterval );
+extern void enable_timer( uint8_t timer_num );
+extern void disable_timer( uint8_t timer_num );
+extern void reset_timer( uint8_t timer_num );
+extern void TIMER0_interrupt (void);
+extern void TIMER1_interrupt (void);
+extern void TIMER2_interrupt (void);
+extern void TIMER3_interrupt (void);
+
+#endif /* end __TIMER_H */
+/*****************************************************************************
+** End Of File
+******************************************************************************/
diff --git a/firmware/drivers/wm8523.c b/firmware/drivers/wm8523.c
index 08b8d97..f8cad99 100644
--- a/firmware/drivers/wm8523.c
+++ b/firmware/drivers/wm8523.c
@@ -26,6 +26,8 @@
*/
#include "wm8523.h"
+#if 1
+
#include <string.h>
#include <cli.h>
@@ -45,7 +47,7 @@ typedef union {
void WM8523_init()
{
- cli_write("sizeof: %d", sizeof(WM8523_transfer_t));
+ //cli_write("sizeof: %d", sizeof(WM8523_transfer_t));
spi_init();
}
@@ -87,9 +89,11 @@ To use volume update in software control mode, I2C mode must be used.
*/
void WM8523_configure()
{
- spi_configure();
+ // spi_init();
uint16_t id = WM8523_read(0); // Read chip id from reg0.
-
- cli_write("=%d=", id); // should be 34595 (0x8523)
+ (void)id;
+ // cli_write("=%d=", id); // should be 34595 (0x8523)
}
+
+#endif/*0*/
diff --git a/firmware/src/p2m.c b/firmware/src/p2m.c
index 11fe393..d44a01c 100644
--- a/firmware/src/p2m.c
+++ b/firmware/src/p2m.c
@@ -6,9 +6,11 @@
#include <LPC17xx.h>
-//#define SPI
-#define IRQ_BLINKY
+//#define IRQ_BLINKY
//#define BLINKY
+//#define BLINKY
+//#define WM8523
+#define SPI
#ifdef DMA
@@ -71,7 +73,7 @@ int main (void)
}
-#endif
+#endif/*IRQ_BLINKY*/
#ifdef BLINKY
@@ -90,7 +92,7 @@ int main (void)
}
-#endif
+#endif/*BLINKY*/
#ifdef UART
@@ -130,9 +132,9 @@ int main (void)
}
}
-#endif
+#endif/*UART*/
-#ifdef SPI
+#ifdef WM8523
#include <cli.h>
#include <wm8523.h>
@@ -145,24 +147,146 @@ int main (void)
LED_Init();
- cli_init();
-
- cli_write("init");
-
_delay(1 << 22);
WM8523_init();
- cli_write("pre");
-
_delay(1 << 22);
WM8523_configure();
- cli_write("post");
+ // Indicate that we didn't crash before the end...
+ int i = 0;
+ while(1) {
+ LED_toggle();
+ _delay(1 << 21);
+ i = 1 - i;
+ }
}
-#endif
+#endif/*WM8523*/
+
+#ifdef SPI
+// 1. Introduction
+/*
+ SPI is one of the most used serial interfaces on PCB level. This tutorial
+ explains how to use SPI to read or write data. For SPI the SPI library is
+ required. It can be downloaded from our repository. The library provides
+ commands for communicating over SPI.
+*/
+
+// 2. Includes
+#include <LPC17xx.h>
+//#include "lpc_types.h"
+#include <ssp.h>
+#include <GPIO.h>
+#include <timer.h>
+#include <led.h>
+
+typedef unsigned char uint8_t;
+
+int main (void)
+{
+ LED_Init(); // Bent code
+
+ // 3. Initializing
+ /*
+ SPI uses 4 IO pins, 1 clock, 1 MOSI, data from master to slave, 1 MISO,
+ data from slave to master and one Chip select pin. Every SPI IC has a Chip
+ Select pin, when the pin is low that IC will be selected to communicate
+ with. Every SPI IC that has a high value on the Chip Select pin will ignore
+ all signals on their data pins. 1 normal IO pin is used for the Chip Select,
+ the clock; MOSI and MISO are SPI pins. Any IO pin can be used for Chip
+ Select, For the tutorial pin 0.0 is used.
+ The timer has to be initialized to use it for delays and the GPIO pin for
+ Chip Select has to be initialized as output and made high, the code for
+ that is:
+ */
+ // TimerInit(0, 1000);
+
+ GPIOSetDir(0, 16, 1);
+ GPIOSetValue(0, 16, 1);
+
+ /*
+ There are 2 SPI channels, SSP0 and SSP1. SSP0 uses pin 0.15 for the clock;
+ pin 0.17 for MISO and pin 0.18 for MOSI. SSP1 uses pin 0.7 for the clock;
+ pin 0.8 for MISO and pin 0.9 for MOSI. To initialize a SPI port the
+ command SSP*channelno*init(); is used. To initialize SPI channel 1 the
+ command is:
+ */
+ SSP0Init();
+
+ /*
+ Some variables are also needed. SPI needs 2 array buffers, one for data
+ that has to be send trough the SPI slave and one for data received from
+ the SPI slave. Also its recommended to declare a variable with the value
+ of the SPI channel that is used:
+ */
+ uint8_t src_addr[16]; //16 byte Write buffer
+ uint8_t dest_addr[16]; //16 byte Read buffer
+ uint8_t portnum = 0;
+
+ // 4. Write data to SPI
+ /*
+ First the Chip Select has to be made low with the GPIOSetValue command:
+ GPIOSetValue(0, 0, 0;)
+ The data that has to be written should be placed in the src_addr array that
+ was declared earlier. To write 5 bytes of data (0x48, 0x65, 0x6c, 0x6c,
+ 0x6f the ascii code for Hello) place the hex data in the buffer array:
+ */
+
+ GPIOSetValue(0, 16, 0);
+
+ src_addr[0] = 0x1 << 7;
+ src_addr[1] = 0xff;
+ src_addr[2] = 0xff;
+
+ /*
+ When the data is stored in the array all that is left is start the SPI data
+ transmission with the SSPSend( portnum, (uint8_t *)src_addr, datanumbers);
+ portnum is the used SPI port, (uint8_t *)src_addr is the send buffer,
+ datanumbers is the amount of databytes to be send. The command needed to
+ send the 5 databytes declared above is:
+ */
+ SSPSend(portnum, (uint8_t *)src_addr, 1);
+
+ /*
+ After the data is send the Chip Select pin needs to be made high again with
+ the command GPIOSetValue(0, 0, 1); . Also a small delay can be needed for
+ some SPI IC’s, 1 millisecond is enough most of the time, the command for a
+ small delay is: delayMs(0, 1);
+ */
+ // delayMs(0, 1);
+
+ // GPIOSetValue(0, 16, 1);
+
+ // 5. Read data from SPI
+ /*
+ To read data the Chip Select has to be made low with GPIOSetValue(0,0,0); .
+ To read data from SPI the command SSPReceive(portnum, (uint8_t *)dest_addr,
+ datanumbers); is used. Portnum is the used SPI port, (uint8_t *)dest_addr
+ is the receive buffer, datanumbers is the amount of databytes that have to
+ be read. A command to read 4 databytes is:
+ */
+ // GPIOSetValue(0, 16, 0);
+
+ SSPReceive(portnum, (uint8_t *)dest_addr, 3);
+
+ GPIOSetValue(0, 16, 1);
+ /*
+ The 4 databytes are now stored in dest_addr[0] to dest_addr[3]
+ */
+
+ // Indicate that we didn't crash before the end...
+ int i = 0;
+ while(1) {
+ LED_toggle();
+ _delay(1 << 21);
+ i = 1 - i;
+ }
+}
+
+#endif/*SPI*/
void _delay(uint32_t del)
{