fix for mbed lib issue 3 (i2c problem) see also https://mbed.org/users/mbed_official/code/mbed/issues/3 affected implementations: LPC812, LPC11U24, LPC1768, LPC2368, LPC4088

Fork of mbed-src by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers spi_api.c Source File

spi_api.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include <math.h>
00017 
00018 #include "spi_api.h"
00019 #include "cmsis.h"
00020 #include "pinmap.h"
00021 #include "error.h"
00022 
00023 static const SWM_Map SWM_SPI_SSEL[] = {
00024     {4, 16},
00025     {5, 16},
00026 };
00027 
00028 static const SWM_Map SWM_SPI_SCLK[] = {
00029     {3, 24},
00030     {4, 24},
00031 };
00032 
00033 static const SWM_Map SWM_SPI_MOSI[] = {
00034     {4, 0},
00035     {5, 0},
00036 };
00037 
00038 static const SWM_Map SWM_SPI_MISO[] = {
00039     {4, 8},
00040     {5, 16},
00041 };
00042 
00043 // bit flags for used SPIs
00044 static unsigned char spi_used = 0;
00045 static int get_available_spi(void) {
00046     int i;
00047     for (i=0; i<2; i++) {
00048         if ((spi_used & (1 << i)) == 0)
00049             return i;
00050     }
00051     return -1;
00052 }
00053 
00054 static inline int ssp_disable(spi_t *obj);
00055 static inline int ssp_enable(spi_t *obj);
00056 
00057 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
00058     int spi_n = get_available_spi();
00059     if (spi_n == -1) {
00060         error("No available SPI");
00061     }
00062     obj->spi_n = spi_n;
00063     spi_used |= (1 << spi_n);
00064     
00065     obj->spi = (spi_n) ? (LPC_SPI_TypeDef *)(LPC_SPI1_BASE) : (LPC_SPI_TypeDef *)(LPC_SPI0_BASE);
00066     
00067     const SWM_Map *swm;
00068     uint32_t regVal;
00069     
00070     swm = &SWM_SPI_SCLK[obj->spi_n];
00071     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00072     LPC_SWM->PINASSIGN[swm->n] = regVal |  (sclk   << swm->offset);
00073     
00074     swm = &SWM_SPI_MOSI[obj->spi_n];
00075     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00076     LPC_SWM->PINASSIGN[swm->n] = regVal |  (mosi   << swm->offset);
00077     
00078     swm = &SWM_SPI_MISO[obj->spi_n];
00079     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00080     LPC_SWM->PINASSIGN[swm->n] = regVal |  (miso   << swm->offset);
00081     
00082     swm = &SWM_SPI_SSEL[obj->spi_n];
00083     regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset);
00084     LPC_SWM->PINASSIGN[swm->n] = regVal |  (ssel   << swm->offset);
00085     
00086     // clear interrupts
00087     obj->spi->INTENCLR = 0x3f;
00088     
00089     // enable power and clocking
00090     switch (obj->spi_n) {
00091         case 0:
00092             LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11);
00093             LPC_SYSCON->PRESETCTRL &= ~(0x1<<0);
00094             LPC_SYSCON->PRESETCTRL |= (0x1<<0);
00095             break;
00096         case 1:
00097             LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12);
00098             LPC_SYSCON->PRESETCTRL &= ~(0x1<<1);
00099             LPC_SYSCON->PRESETCTRL |= (0x1<<1);
00100             break;
00101     }
00102     
00103     // set default format and frequency
00104     if (ssel == NC) {
00105         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
00106     } else {
00107         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
00108     }
00109     spi_frequency(obj, 1000000);
00110     
00111     // enable the ssp channel
00112     ssp_enable(obj);
00113 }
00114 
00115 void spi_free(spi_t *obj) {}
00116 
00117 void spi_format(spi_t *obj, int bits, int mode, int slave) {
00118     ssp_disable(obj);
00119     
00120     if (!(bits >= 1 && bits <= 16) || !(mode >= 0 && mode <= 3)) {
00121         error("SPI format error");
00122     }
00123     
00124     
00125     int polarity = (mode & 0x2) ? 1 : 0;
00126     int phase = (mode & 0x1) ? 1 : 0;
00127     
00128     // set it up
00129     int DSS = bits - 1;            // DSS (data select size)
00130     int SPO = (polarity) ? 1 : 0;  // SPO - clock out polarity
00131     int SPH = (phase) ? 1 : 0;     // SPH - clock out phase
00132     
00133     uint32_t tmp = obj->spi->CFG;
00134     tmp &= ~((1 << 2) | (1 << 4) | (1 << 5));
00135     tmp |= (SPH << 4) | (SPO << 5) | ((slave ? 0 : 1) << 2);
00136     obj->spi->CFG = tmp;
00137     
00138     // select frame length
00139     tmp = obj->spi->TXDATCTL;
00140     tmp &= ~(0xf << 24);
00141     tmp |= (DSS << 24);
00142     obj->spi->TXDATCTL = tmp;
00143     
00144     ssp_enable(obj);
00145 }
00146 
00147 void spi_frequency(spi_t *obj, int hz) {
00148     ssp_disable(obj);
00149     
00150     uint32_t PCLK = SystemCoreClock;
00151     
00152     obj->spi->DIV = PCLK/hz - 1;
00153     obj->spi->DLY = 0;
00154     ssp_enable(obj);
00155 }
00156 
00157 static inline int ssp_disable(spi_t *obj) {
00158     return obj->spi->CFG &= ~(1 << 0);
00159 }
00160 
00161 static inline int ssp_enable(spi_t *obj) {
00162     return obj->spi->CFG |= (1 << 0);
00163 }
00164 
00165 static inline int ssp_readable(spi_t *obj) {
00166     return obj->spi->STAT & (1 << 0);
00167 }
00168 
00169 static inline int ssp_writeable(spi_t *obj) {
00170     return obj->spi->STAT & (1 << 1);
00171 }
00172 
00173 static inline void ssp_write(spi_t *obj, int value) {
00174     while (!ssp_writeable(obj));
00175     // end of transfer
00176     obj->spi->TXDATCTL |= (1 << 20);
00177     obj->spi->TXDAT = value;
00178 }
00179 
00180 static inline int ssp_read(spi_t *obj) {
00181     while (!ssp_readable(obj));
00182     return obj->spi->RXDAT;
00183 }
00184 
00185 static inline int ssp_busy(spi_t *obj) {
00186     // TODO
00187     return 0;
00188 }
00189 
00190 int spi_master_write(spi_t *obj, int value) {
00191     ssp_write(obj, value);
00192     return ssp_read(obj);
00193 }
00194 
00195 int spi_slave_receive(spi_t *obj) {
00196     return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0);
00197 };
00198 
00199 int spi_slave_read(spi_t *obj) {
00200     return obj->spi->RXDAT;
00201 }
00202 
00203 void spi_slave_write(spi_t *obj, int value) {
00204     while (ssp_writeable(obj) == 0) ;
00205     obj->spi->TXDAT = value;
00206 }
00207 
00208 int spi_busy(spi_t *obj) {
00209     return ssp_busy(obj);
00210 }