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