/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * spi.c * * Sun Jun 9 14:02:49 CEST 2013 * Copyright 2013 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of Pedal2Metal. * * Pedal2Metal is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Pedal2Metal is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Pedal2Metal; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "spi.h" #include #define USE_CMSIS #ifdef USE_CMSIS #include #include LPC_SPI_TypeDef *spi; #else/*USE_CMSIS*/ // 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 // Clock speed devisors. Values for PCLKSEL0 register (See table 42) 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; // PINSEL0 function value for SCK0 function (see table 79) #define SCK0_FUNCTION 0x2 #define SCK0_BIT 30 // PINSEL1 function value for SSEL0 function (see table 80) #define SSEL0_FUNCTION 0x2 #define SSEL0_BIT 0 // PINSEL1 function value for MISO0 function (see table 80) #define MISO0_FUNCTION 0x2 #define MISO0_BIT 2 // PINSEL1 function value for MOSI0 function (see table 80) #define MOSI0_FUNCTION 0x2 #define MOSI0_BIT 4 #endif/*USE_CMSIS*/ /** * Initialisation as described in "17.1 Basic Configuration" */ void spi_init() { #ifdef USE_CMSIS SPI_CFG_Type spi_cfg; // 16 bit data transfers spi_cfg.Databit = SPI_DATABIT_8; // WM8523 samples bits on rising edges. Mode 0 or 3 will work // http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase // Mode 0 spi_cfg.CPHA = SPI_CPHA_FIRST; // 0 spi_cfg.CPOL = SPI_CPOL_HI; // 0 /* // Mode 3 spi_cfg.CPHA = SPI_CPHA_SECOND; // 1 spi_cfg.CPOL = SPI_CPOL_LO; // 1 */ // We are the master spi_cfg.Mode = SPI_MASTER_MODE; // We run on a little endian mcu. 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 = LPC_SPI; SPI_Init(spi, &spi_cfg); NVIC_EnableIRQ(SPI_IRQn); #else/*USE_CMSIS*/ // 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) // Set clock speed (indirectly as clock devisor) 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 // Make pin selection for SPI. // SCK0: P1.20 // SSEL0: P1.21 // MOSI0: P1.23 // MISO0: P1.24 LPC_PINCON->PINSEL0 &= ~(0x3 << SCK0_BIT); LPC_PINCON->PINSEL0 |= (SCK0_FUNCTION << SCK0_BIT); LPC_PINCON->PINSEL1 &= ~(0x3 << SSEL0_BIT); LPC_PINCON->PINSEL1 |= (SSEL0_FUNCTION << SSEL0_BIT); LPC_PINCON->PINSEL1 &= ~(0x3 << MISO0_BIT); LPC_PINCON->PINSEL1 |= (MISO0_FUNCTION << MISO0_BIT); LPC_PINCON->PINSEL1 &= ~(0x3 << MOSI0_BIT); LPC_PINCON->PINSEL1 |= (MOSI0_FUNCTION << MOSI0_BIT); // Enable SPI interrupt: // Set SPI interrupt flag (see table 367) LPC_SPI->SPINT = 1; // Enable SPI interrupt in the NVIC (see table 50) NVIC_EnableIRQ(SPI_IRQn); #endif/*USE_CMSIS*/ // Configure SSEL pin: LPC_GPIO1->FIODIR |= 1 << 21; // Set 1.21 in output mode } void spi_deinit() { #ifdef USE_CMSIS #else/*USE_CMSIS*/ // Power down SPI LPC_SC->PCONP &= ~(1 << PCSPI_BIT); // unset bit 8 in PCONP (PCSPI bit) #endif/*USE_CMSIS*/ } // S0SPCR register (see table 361) #define BENA 0 // Enable more than 8 bit transactions #define CPHA 0 // CPHA (Clock Phase Control) \ _ Mode 0 #define CPOL 0 // CPOL (Clock Polarity Control) / #define MSTR 1 // MSTR (Master Mode Select) #define LSB 1 // LSB vs MSB #define SPIE 1 // Enable interrupts #define BITS 0 // Bits to transfer, only use if BENA is set to 1 void spi_configure() { #ifdef USE_CMSIS #else/*USE_CMSIS*/ // S0SPCR register (see table 361) LPC_SPI->SPCR = (BENA << 2) | (CPHA << 3) | (CPOL << 4) | (MSTR << 5) | (LSB << 6) | (SPIE << 7) | (BITS << 8); LPC_SPI->SPCCR = 1; #endif/*USE_CMSIS*/ } static volatile int spi_done = 0; static void spi_mark_as_done() { spi_done = 1; } volatile int temp; void __delay(uint32_t del) { uint32_t i; for(i=0;iFIOPIN &= ~( 1 << 21 ); // make P1.21 low spi_done = 0; SPI_ReadWrite(spi, &dst, SPI_TRANSFER_POLLING);//SPI_TRANSFER_INTERRUPT); cli_write(">"); while (!(SPI_GetStatus(spi) & SPI_SPSR_SPIF)) { } //while(!spi_done) {} cli_write("<"); LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high #else/*USE_CMSIS*/ int i = 0; cli_write(">>"); LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low for(; i < length; i++) { /* cli_write("w"); LPC_GPIO1->FIOPIN &= ~( 1 << 21 ); // make P1.21 low __delay(1 << 23); */ //LPC_SPI->SPINT = 1; // Clear interrupt (see section 17.7.7) //if(LPC_SPI->SPSR) {} // Make sure we clear the status register LPC_SPI->SPDR = tx_data[i]; //cli_write("[%d]", tx_data[i]); //if(LPC_SPI->SPSR) {} // Make sure we clear the status register // Check SPIF bit (see table 362) //while(((LPC_SPI->SPSR << 7) & 0x1) != 1) {} //while(LPC_SPI->SPSR == 0) {} // Wait for status register while(LPC_SPI->SPINT == 0) {} // Wait for interrupt LPC_SPI->SPINT = 1; //__delay(1 << 23); // cli_write("{%d}", LPC_SPI->SPSR); rx_data[i] = LPC_SPI->SPDR; //cli_write("[%d]", rx_data[i]); /* cli_write("r"); LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high __delay(1 << 23); */ } LPC_GPIO1->FIOPIN |= 1 << 21; // make P1.29 high cli_write("<<"); #endif/*USE_CMSIS*/ }