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 PinMap PinMap_SPI_SCLK[] = {
00024     {P0_7 , SPI_1, 2},
00025     {P0_15, SPI_0, 2},
00026     {P1_0,  SPI_2, 4},
00027     {P1_19, SPI_1, 5},
00028     {P1_20, SPI_0, 5},
00029     {P1_31, SPI_1, 2},
00030     {P2_22, SPI_0, 2},
00031     {P4_20, SPI_1, 3},
00032     {P5_2,  SPI_2, 2},
00033     {NC   , NC   , 0}
00034 };
00035 
00036 static const PinMap PinMap_SPI_MOSI[] = {
00037     {P0_9 , SPI_1, 2},
00038     {P0_13, SPI_1, 2},
00039     {P0_18, SPI_0, 2},
00040     {P1_1,  SPI_2, 4},
00041     {P1_22, SPI_1, 5},
00042     {P1_24, SPI_0, 5},
00043     {P2_27, SPI_0, 2},
00044     {P4_23, SPI_1, 3},
00045     {P5_0,  SPI_2, 2},
00046     {NC   , NC   , 0}
00047 };
00048 
00049 static const PinMap PinMap_SPI_MISO[] = {
00050     {P0_8 , SPI_1, 2},
00051     {P0_12, SPI_1, 2},
00052     {P0_17, SPI_0, 2},
00053     {P1_4,  SPI_2, 4},
00054     {P1_18, SPI_1, 5},
00055     {P1_23, SPI_0, 5},
00056     {P2_26, SPI_0, 2},
00057     {P4_22, SPI_1, 3},
00058     {P5_1,  SPI_2, 2},
00059     {NC   , NC   , 0}
00060 };
00061 
00062 static const PinMap PinMap_SPI_SSEL[] = {
00063     {P0_6 , SPI_1, 2},
00064     {P0_14, SPI_1, 2},
00065     {P0_16, SPI_0, 2},
00066     {P1_8,  SPI_2, 4},
00067     {P1_21, SPI_0, 3},
00068     {P1_26, SPI_1, 5},
00069     {P1_28, SPI_0, 5},
00070     {P2_23, SPI_0, 2},
00071     {P4_21, SPI_1, 3},
00072     {NC   , NC   , 0}
00073 };
00074 
00075 static inline int ssp_disable(spi_t *obj);
00076 static inline int ssp_enable(spi_t *obj);
00077 
00078 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
00079     // determine the SPI to use
00080     SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
00081     SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
00082     SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
00083     SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
00084     SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
00085     SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
00086     obj->spi = (LPC_SSP_TypeDef*)pinmap_merge(spi_data, spi_cntl);
00087     if ((int)obj->spi == NC) {
00088         error("SPI pinout mapping failed");
00089     }
00090     
00091     // enable power and clocking
00092     switch ((int)obj->spi) {
00093         case SPI_0: LPC_SC->PCONP |= 1 << 21; break;
00094         case SPI_1: LPC_SC->PCONP |= 1 << 10; break;
00095         case SPI_2: LPC_SC->PCONP |= 1 << 20; break;
00096     }
00097     
00098     // set default format and frequency
00099     if (ssel == NC) {
00100         spi_format(obj, 8, 0, 0);  // 8 bits, mode 0, master
00101     } else {
00102         spi_format(obj, 8, 0, 1);  // 8 bits, mode 0, slave
00103     }
00104     spi_frequency(obj, 1000000);
00105     
00106     // enable the ssp channel
00107     ssp_enable(obj);
00108     
00109     // pin out the spi pins
00110     pinmap_pinout(mosi, PinMap_SPI_MOSI);
00111     pinmap_pinout(miso, PinMap_SPI_MISO);
00112     pinmap_pinout(sclk, PinMap_SPI_SCLK);
00113     if (ssel != NC) {
00114         pinmap_pinout(ssel, PinMap_SPI_SSEL);
00115     }
00116 }
00117 
00118 void spi_free(spi_t *obj) {}
00119 
00120 void spi_format(spi_t *obj, int bits, int mode, int slave) {
00121     ssp_disable(obj);
00122     
00123     if (!(bits >= 4 && bits <= 16) || !(mode >= 0 && mode <= 3)) {
00124         error("SPI format error");
00125     }
00126     
00127     int polarity = (mode & 0x2) ? 1 : 0;
00128     int phase = (mode & 0x1) ? 1 : 0;
00129     
00130     // set it up
00131     int DSS = bits - 1;            // DSS (data select size)
00132     int SPO = (polarity) ? 1 : 0;  // SPO - clock out polarity
00133     int SPH = (phase) ? 1 : 0;     // SPH - clock out phase
00134     
00135     int FRF = 0;                   // FRF (frame format) = SPI
00136     uint32_t tmp = obj->spi->CR0;
00137     tmp &= ~(0xFFFF);
00138     tmp |= DSS << 0
00139         | FRF << 4
00140         | SPO << 6
00141         | SPH << 7;
00142     obj->spi->CR0 = tmp;
00143     
00144     tmp = obj->spi->CR1;
00145     tmp &= ~(0xD);
00146     tmp |= 0 << 0                   // LBM - loop back mode - off
00147         | ((slave) ? 1 : 0) << 2   // MS - master slave mode, 1 = slave
00148         | 0 << 3;                  // SOD - slave output disable - na
00149     obj->spi->CR1 = tmp;
00150     ssp_enable(obj);
00151 }
00152 
00153 void spi_frequency(spi_t *obj, int hz) {
00154     ssp_disable(obj);
00155     
00156     uint32_t PCLK = PeripheralClock ;
00157     
00158     int prescaler;
00159     
00160     for (prescaler = 2; prescaler <= 254; prescaler += 2) {
00161         int prescale_hz = PCLK / prescaler;
00162         
00163         // calculate the divider
00164         int divider = floor(((float)prescale_hz / (float)hz) + 0.5f);
00165         
00166         // check we can support the divider
00167         if (divider < 256) {
00168             // prescaler
00169             obj->spi->CPSR = prescaler;
00170             
00171             // divider
00172             obj->spi->CR0 &= ~(0xFFFF << 8);
00173             obj->spi->CR0 |= (divider - 1) << 8;
00174             ssp_enable(obj);
00175             return;
00176         }
00177     }
00178     error("Couldn't setup requested SPI frequency");
00179 }
00180 
00181 static inline int ssp_disable(spi_t *obj) {
00182     return obj->spi->CR1 &= ~(1 << 1);
00183 }
00184 
00185 static inline int ssp_enable(spi_t *obj) {
00186     return obj->spi->CR1 |= (1 << 1);
00187 }
00188 
00189 static inline int ssp_readable(spi_t *obj) {
00190     return obj->spi->SR & (1 << 2);
00191 }
00192 
00193 static inline int ssp_writeable(spi_t *obj) {
00194     return obj->spi->SR & (1 << 1);
00195 }
00196 
00197 static inline void ssp_write(spi_t *obj, int value) {
00198     while (!ssp_writeable(obj));
00199     obj->spi->DR = value;
00200 }
00201 
00202 static inline int ssp_read(spi_t *obj) {
00203     while (!ssp_readable(obj));
00204     return obj->spi->DR;
00205 }
00206 
00207 static inline int ssp_busy(spi_t *obj) {
00208     return (obj->spi->SR & (1 << 4)) ? (1) : (0);
00209 }
00210 
00211 int spi_master_write(spi_t *obj, int value) {
00212     ssp_write(obj, value);
00213     return ssp_read(obj);
00214 }
00215 
00216 int spi_slave_receive(spi_t *obj) {
00217     return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0);
00218 };
00219 
00220 int spi_slave_read(spi_t *obj) {
00221     return obj->spi->DR;
00222 }
00223 
00224 void spi_slave_write(spi_t *obj, int value) {
00225     while (ssp_writeable(obj) == 0) ;
00226     obj->spi->DR = value;
00227 }
00228 
00229 int spi_busy(spi_t *obj) {
00230     return ssp_busy(obj);
00231 }