Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 "spi_api.h" 00017 00018 #if DEVICE_SPI 00019 #include <math.h> 00020 00021 #include "cmsis.h" 00022 #include "pinmap.h" 00023 #include "error.h" 00024 00025 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00026 00027 static const PinMap PinMap_SPI_SCLK[] = { 00028 {P0_7 , SPI_1, 2}, 00029 {P0_15, SPI_0, 2}, 00030 {P1_20, SPI_0, 3}, 00031 {P1_31, SPI_1, 2}, 00032 {NC , NC , 0} 00033 }; 00034 00035 static const PinMap PinMap_SPI_MOSI[] = { 00036 {P0_9 , SPI_1, 2}, 00037 {P0_13, SPI_1, 2}, 00038 {P0_18, SPI_0, 2}, 00039 {P1_24, SPI_0, 3}, 00040 {NC , NC , 0} 00041 }; 00042 00043 static const PinMap PinMap_SPI_MISO[] = { 00044 {P0_8 , SPI_1, 2}, 00045 {P0_12, SPI_1, 2}, 00046 {P0_17, SPI_0, 2}, 00047 {P1_23, SPI_0, 3}, 00048 {NC , NC , 0} 00049 }; 00050 00051 static const PinMap PinMap_SPI_SSEL[] = { 00052 {P0_6 , SPI_1, 2}, 00053 {P0_11, SPI_1, 2}, 00054 {P0_16, SPI_0, 2}, 00055 {P1_21, SPI_0, 3}, 00056 {NC , NC , 0} 00057 }; 00058 00059 #elif defined(TARGET_LPC11U24) 00060 00061 static const PinMap PinMap_SPI_SCLK[] = { 00062 {P0_6 , SPI_0, 0x02}, 00063 {P0_10, SPI_0, 0x02}, 00064 {P1_29, SPI_0, 0x01}, 00065 {P1_15, SPI_1, 0x03}, 00066 {P1_20, SPI_1, 0x02}, 00067 {NC , NC , 0} 00068 }; 00069 00070 static const PinMap PinMap_SPI_MOSI[] = { 00071 {P0_9 , SPI_0, 0x01}, 00072 {P0_21, SPI_1, 0x02}, 00073 {P1_22, SPI_1, 0x02}, 00074 {NC , NC , 0} 00075 }; 00076 00077 static const PinMap PinMap_SPI_MISO[] = { 00078 {P0_8 , SPI_0, 0x01}, 00079 {P0_22, SPI_1, 0x03}, 00080 {P1_21, SPI_1, 0x02}, 00081 {NC , NC , 0} 00082 }; 00083 00084 static const PinMap PinMap_SPI_SSEL[] = { 00085 {P0_2 , SPI_0, 0x01}, 00086 {P1_19, SPI_1, 0x02}, 00087 {P1_23, SPI_1, 0x02}, 00088 {NC , NC , 0} 00089 }; 00090 00091 #elif defined(TARGET_LPC812) 00092 00093 static const SWM_Map SWM_SPI_SSEL[] = { 00094 {4, 16}, 00095 {5, 16}, 00096 }; 00097 00098 static const SWM_Map SWM_SPI_SCLK[] = { 00099 {3, 24}, 00100 {4, 24}, 00101 }; 00102 00103 static const SWM_Map SWM_SPI_MOSI[] = { 00104 {4, 0}, 00105 {5, 0}, 00106 }; 00107 00108 static const SWM_Map SWM_SPI_MISO[] = { 00109 {4, 8}, 00110 {5, 16}, 00111 }; 00112 00113 // bit flags for used SPIs 00114 static unsigned char spi_used = 0; 00115 static int get_available_spi(void) { 00116 int i; 00117 for (i=0; i<2; i++) { 00118 if ((spi_used & (1 << i)) == 0) 00119 return i; 00120 } 00121 return -1; 00122 } 00123 00124 #endif 00125 00126 static inline int ssp_disable(spi_t *obj); 00127 static inline int ssp_enable(spi_t *obj); 00128 00129 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) { 00130 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00131 // determine the SPI to use 00132 SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI); 00133 SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO); 00134 SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK); 00135 SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL); 00136 SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso); 00137 SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel); 00138 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00139 obj->spi = (LPC_SSP_TypeDef*)pinmap_merge(spi_data, spi_cntl); 00140 #elif defined(TARGET_LPC11U24) 00141 obj->spi = (LPC_SSPx_Type*)pinmap_merge(spi_data, spi_cntl); 00142 #endif 00143 if ((int)obj->spi == NC) { 00144 error("SPI pinout mapping failed"); 00145 } 00146 #elif defined(TARGET_LPC812) 00147 int spi_n = get_available_spi(); 00148 if (spi_n == -1) { 00149 error("No available SPI"); 00150 } 00151 obj->spi_n = spi_n; 00152 spi_used |= (1 << spi_n); 00153 00154 obj->spi = (spi_n) ? (LPC_SPI_TypeDef *)(LPC_SPI1_BASE) : (LPC_SPI_TypeDef *)(LPC_SPI0_BASE); 00155 00156 const SWM_Map *swm; 00157 uint32_t regVal; 00158 00159 swm = &SWM_SPI_SCLK[obj->spi_n]; 00160 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset); 00161 LPC_SWM->PINASSIGN[swm->n] = regVal | (sclk << swm->offset); 00162 00163 swm = &SWM_SPI_MOSI[obj->spi_n]; 00164 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset); 00165 LPC_SWM->PINASSIGN[swm->n] = regVal | (mosi << swm->offset); 00166 00167 swm = &SWM_SPI_MISO[obj->spi_n]; 00168 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset); 00169 LPC_SWM->PINASSIGN[swm->n] = regVal | (miso << swm->offset); 00170 00171 swm = &SWM_SPI_SSEL[obj->spi_n]; 00172 regVal = LPC_SWM->PINASSIGN[swm->n] & ~(0xFF << swm->offset); 00173 LPC_SWM->PINASSIGN[swm->n] = regVal | (ssel << swm->offset); 00174 00175 // clear interrupts 00176 obj->spi->INTENCLR = 0x3f; 00177 #endif 00178 00179 // enable power and clocking 00180 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00181 switch ((int)obj->spi) { 00182 case SPI_0: LPC_SC->PCONP |= 1 << 21; break; 00183 case SPI_1: LPC_SC->PCONP |= 1 << 10; break; 00184 } 00185 #elif defined(TARGET_LPC11U24) 00186 switch ((int)obj->spi) { 00187 case SPI_0: 00188 LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 11; 00189 LPC_SYSCON->SSP0CLKDIV = 0x01; 00190 LPC_SYSCON->PRESETCTRL |= 1 << 0; 00191 break; 00192 case SPI_1: 00193 LPC_SYSCON->SYSAHBCLKCTRL |= 1 << 18; 00194 LPC_SYSCON->SSP1CLKDIV = 0x01; 00195 LPC_SYSCON->PRESETCTRL |= 1 << 2; 00196 break; 00197 } 00198 #elif defined(TARGET_LPC812) 00199 switch (obj->spi_n) { 00200 case 0: 00201 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11); 00202 LPC_SYSCON->PRESETCTRL &= ~(0x1<<0); 00203 LPC_SYSCON->PRESETCTRL |= (0x1<<0); 00204 break; 00205 case 1: 00206 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<12); 00207 LPC_SYSCON->PRESETCTRL &= ~(0x1<<1); 00208 LPC_SYSCON->PRESETCTRL |= (0x1<<1); 00209 break; 00210 } 00211 00212 #endif 00213 00214 // set default format and frequency 00215 if (ssel == NC) { 00216 spi_format(obj, 8, 0, 0); // 8 bits, mode 0, master 00217 } else { 00218 spi_format(obj, 8, 0, 1); // 8 bits, mode 0, slave 00219 } 00220 spi_frequency(obj, 1000000); 00221 00222 // enable the ssp channel 00223 ssp_enable(obj); 00224 00225 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00226 // pin out the spi pins 00227 pinmap_pinout(mosi, PinMap_SPI_MOSI); 00228 pinmap_pinout(miso, PinMap_SPI_MISO); 00229 pinmap_pinout(sclk, PinMap_SPI_SCLK); 00230 if (ssel != NC) { 00231 pinmap_pinout(ssel, PinMap_SPI_SSEL); 00232 } 00233 #endif 00234 } 00235 00236 void spi_free(spi_t *obj) {} 00237 00238 void spi_format(spi_t *obj, int bits, int mode, int slave) { 00239 ssp_disable(obj); 00240 00241 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00242 if (!(bits >= 4 && bits <= 16) || !(mode >= 0 && mode <= 3)) { 00243 #elif defined(TARGET_LPC812) 00244 if (!(bits >= 1 && bits <= 16) || !(mode >= 0 && mode <= 3)) { 00245 #endif 00246 error("SPI format error"); 00247 } 00248 00249 00250 int polarity = (mode & 0x2) ? 1 : 0; 00251 int phase = (mode & 0x1) ? 1 : 0; 00252 00253 // set it up 00254 int DSS = bits - 1; // DSS (data select size) 00255 int SPO = (polarity) ? 1 : 0; // SPO - clock out polarity 00256 int SPH = (phase) ? 1 : 0; // SPH - clock out phase 00257 00258 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00259 int FRF = 0; // FRF (frame format) = SPI 00260 uint32_t tmp = obj->spi->CR0; 00261 tmp &= ~(0xFFFF); 00262 tmp |= DSS << 0 00263 | FRF << 4 00264 | SPO << 6 00265 | SPH << 7; 00266 obj->spi->CR0 = tmp; 00267 00268 tmp = obj->spi->CR1; 00269 tmp &= ~(0xD); 00270 tmp |= 0 << 0 // LBM - loop back mode - off 00271 | ((slave) ? 1 : 0) << 2 // MS - master slave mode, 1 = slave 00272 | 0 << 3; // SOD - slave output disable - na 00273 obj->spi->CR1 = tmp; 00274 #elif defined(TARGET_LPC812) 00275 uint32_t tmp = obj->spi->CFG; 00276 tmp &= ~((1 << 2) | (1 << 4) | (1 << 5)); 00277 tmp |= (SPH << 4) | (SPO << 5) | ((slave ? 0 : 1) << 2); 00278 obj->spi->CFG = tmp; 00279 00280 // select frame length 00281 tmp = obj->spi->TXDATCTL; 00282 tmp &= ~(0xf << 24); 00283 tmp |= (DSS << 24); 00284 obj->spi->TXDATCTL = tmp; 00285 #endif 00286 00287 ssp_enable(obj); 00288 } 00289 00290 void spi_frequency(spi_t *obj, int hz) { 00291 ssp_disable(obj); 00292 00293 // setup the spi clock diveder to /1 00294 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) 00295 switch ((int)obj->spi) { 00296 case SPI_0: 00297 LPC_SC->PCLKSEL1 &= ~(3 << 10); 00298 LPC_SC->PCLKSEL1 |= (1 << 10); 00299 break; 00300 case SPI_1: 00301 LPC_SC->PCLKSEL0 &= ~(3 << 20); 00302 LPC_SC->PCLKSEL0 |= (1 << 20); 00303 break; 00304 } 00305 #endif 00306 00307 uint32_t PCLK = SystemCoreClock ; 00308 00309 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00310 int prescaler; 00311 00312 for (prescaler = 2; prescaler <= 254; prescaler += 2) { 00313 int prescale_hz = PCLK / prescaler; 00314 00315 // calculate the divider 00316 int divider = floor(((float)prescale_hz / (float)hz) + 0.5); 00317 00318 // check we can support the divider 00319 if (divider < 256) { 00320 // prescaler 00321 obj->spi->CPSR = prescaler; 00322 00323 // divider 00324 obj->spi->CR0 &= ~(0xFFFF << 8); 00325 obj->spi->CR0 |= (divider - 1) << 8; 00326 ssp_enable(obj); 00327 return; 00328 } 00329 } 00330 error("Couldn't setup requested SPI frequency"); 00331 #elif defined(TARGET_LPC812) 00332 obj->spi->DIV = PCLK/hz - 1; 00333 obj->spi->DLY = 0; 00334 ssp_enable(obj); 00335 #endif 00336 } 00337 00338 static inline int ssp_disable(spi_t *obj) { 00339 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00340 return obj->spi->CR1 &= ~(1 << 1); 00341 #elif defined(TARGET_LPC812) 00342 return obj->spi->CFG &= ~(1 << 0); 00343 #endif 00344 } 00345 00346 static inline int ssp_enable(spi_t *obj) { 00347 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00348 return obj->spi->CR1 |= (1 << 1); 00349 #elif defined(TARGET_LPC812) 00350 return obj->spi->CFG |= (1 << 0); 00351 #endif 00352 } 00353 00354 static inline int ssp_readable(spi_t *obj) { 00355 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00356 return obj->spi->SR & (1 << 2); 00357 #elif defined(TARGET_LPC812) 00358 return obj->spi->STAT & (1 << 0); 00359 #endif 00360 } 00361 00362 static inline int ssp_writeable(spi_t *obj) { 00363 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00364 return obj->spi->SR & (1 << 1); 00365 #elif defined(TARGET_LPC812) 00366 return obj->spi->STAT & (1 << 1); 00367 #endif 00368 } 00369 00370 static inline void ssp_write(spi_t *obj, int value) { 00371 while (!ssp_writeable(obj)); 00372 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00373 obj->spi->DR = value; 00374 #elif defined(TARGET_LPC812) 00375 // end of transfer 00376 obj->spi->TXDATCTL |= (1 << 20); 00377 obj->spi->TXDAT = value; 00378 #endif 00379 } 00380 00381 static inline int ssp_read(spi_t *obj) { 00382 while (!ssp_readable(obj)); 00383 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00384 return obj->spi->DR; 00385 #elif defined(TARGET_LPC812) 00386 return obj->spi->RXDAT; 00387 #endif 00388 } 00389 00390 static inline int ssp_busy(spi_t *obj) { 00391 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00392 return (obj->spi->SR & (1 << 4)) ? (1) : (0); 00393 #elif defined(TARGET_LPC812) 00394 // TODO 00395 return 0; 00396 #endif 00397 } 00398 00399 int spi_master_write(spi_t *obj, int value) { 00400 ssp_write(obj, value); 00401 return ssp_read(obj); 00402 } 00403 00404 int spi_slave_receive(spi_t *obj) { 00405 return (ssp_readable(obj) && !ssp_busy(obj)) ? (1) : (0); 00406 }; 00407 00408 int spi_slave_read(spi_t *obj) { 00409 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00410 return obj->spi->DR; 00411 #elif defined(TARGET_LPC812) 00412 return obj->spi->RXDAT; 00413 #endif 00414 } 00415 00416 void spi_slave_write(spi_t *obj, int value) { 00417 while (ssp_writeable(obj) == 0) ; 00418 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368) || defined(TARGET_LPC11U24) 00419 obj->spi->DR = value; 00420 #elif defined(TARGET_LPC812) 00421 obj->spi->TXDAT = value; 00422 #endif 00423 } 00424 00425 int spi_busy(spi_t *obj) { 00426 return ssp_busy(obj); 00427 } 00428 00429 #endif
Generated on Thu Jul 14 2022 07:43:04 by
1.7.2