mbed library sources

Dependents:   Nucleo_blink_led

Fork of mbed-src by mbed official

Committer:
emilmont
Date:
Fri Jun 14 17:49:17 2013 +0100
Revision:
10:3bc89ef62ce7
Unify mbed library sources

Who changed what in which revision?

UserRevisionLine numberNew contents of line
emilmont 10:3bc89ef62ce7 1 /* mbed Microcontroller Library
emilmont 10:3bc89ef62ce7 2 * Copyright (c) 2006-2013 ARM Limited
emilmont 10:3bc89ef62ce7 3 *
emilmont 10:3bc89ef62ce7 4 * Licensed under the Apache License, Version 2.0 (the "License");
emilmont 10:3bc89ef62ce7 5 * you may not use this file except in compliance with the License.
emilmont 10:3bc89ef62ce7 6 * You may obtain a copy of the License at
emilmont 10:3bc89ef62ce7 7 *
emilmont 10:3bc89ef62ce7 8 * http://www.apache.org/licenses/LICENSE-2.0
emilmont 10:3bc89ef62ce7 9 *
emilmont 10:3bc89ef62ce7 10 * Unless required by applicable law or agreed to in writing, software
emilmont 10:3bc89ef62ce7 11 * distributed under the License is distributed on an "AS IS" BASIS,
emilmont 10:3bc89ef62ce7 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
emilmont 10:3bc89ef62ce7 13 * See the License for the specific language governing permissions and
emilmont 10:3bc89ef62ce7 14 * limitations under the License.
emilmont 10:3bc89ef62ce7 15 */
emilmont 10:3bc89ef62ce7 16 #include "spi_api.h"
emilmont 10:3bc89ef62ce7 17
emilmont 10:3bc89ef62ce7 18 #include <math.h>
emilmont 10:3bc89ef62ce7 19
emilmont 10:3bc89ef62ce7 20 #include "cmsis.h"
emilmont 10:3bc89ef62ce7 21 #include "pinmap.h"
emilmont 10:3bc89ef62ce7 22 #include "error.h"
emilmont 10:3bc89ef62ce7 23
emilmont 10:3bc89ef62ce7 24 static const PinMap PinMap_SPI_SCLK[] = {
emilmont 10:3bc89ef62ce7 25 {PTE2, SPI_1, 2},
emilmont 10:3bc89ef62ce7 26 {PTC5, SPI_0, 2},
emilmont 10:3bc89ef62ce7 27 {PTD1, SPI_0, 2},
emilmont 10:3bc89ef62ce7 28 {NC , NC , 0}
emilmont 10:3bc89ef62ce7 29 };
emilmont 10:3bc89ef62ce7 30
emilmont 10:3bc89ef62ce7 31 static const PinMap PinMap_SPI_MOSI[] = {
emilmont 10:3bc89ef62ce7 32 {PTE1, SPI_1, 2},
emilmont 10:3bc89ef62ce7 33 {PTC6, SPI_0, 2},
emilmont 10:3bc89ef62ce7 34 {PTD2, SPI_0, 2},
emilmont 10:3bc89ef62ce7 35 {NC , NC , 0}
emilmont 10:3bc89ef62ce7 36 };
emilmont 10:3bc89ef62ce7 37
emilmont 10:3bc89ef62ce7 38 static const PinMap PinMap_SPI_MISO[] = {
emilmont 10:3bc89ef62ce7 39 {PTE3, SPI_1, 2},
emilmont 10:3bc89ef62ce7 40 {PTC7, SPI_0, 2},
emilmont 10:3bc89ef62ce7 41 {PTD3, SPI_0, 2},
emilmont 10:3bc89ef62ce7 42 {NC , NC , 0}
emilmont 10:3bc89ef62ce7 43 };
emilmont 10:3bc89ef62ce7 44
emilmont 10:3bc89ef62ce7 45 static const PinMap PinMap_SPI_SSEL[] = {
emilmont 10:3bc89ef62ce7 46 {PTE4, SPI_1, 2},
emilmont 10:3bc89ef62ce7 47 {PTC4, SPI_0, 2},
emilmont 10:3bc89ef62ce7 48 {PTD0, SPI_0, 2},
emilmont 10:3bc89ef62ce7 49 {NC , NC , 0}
emilmont 10:3bc89ef62ce7 50 };
emilmont 10:3bc89ef62ce7 51
emilmont 10:3bc89ef62ce7 52 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) {
emilmont 10:3bc89ef62ce7 53 // determine the SPI to use
emilmont 10:3bc89ef62ce7 54 SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
emilmont 10:3bc89ef62ce7 55 SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
emilmont 10:3bc89ef62ce7 56 SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
emilmont 10:3bc89ef62ce7 57 SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
emilmont 10:3bc89ef62ce7 58 SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
emilmont 10:3bc89ef62ce7 59 SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
emilmont 10:3bc89ef62ce7 60
emilmont 10:3bc89ef62ce7 61 obj->spi = (SPI_Type*)pinmap_merge(spi_data, spi_cntl);
emilmont 10:3bc89ef62ce7 62 if ((int)obj->spi == NC) {
emilmont 10:3bc89ef62ce7 63 error("SPI pinout mapping failed");
emilmont 10:3bc89ef62ce7 64 }
emilmont 10:3bc89ef62ce7 65
emilmont 10:3bc89ef62ce7 66 // enable power and clocking
emilmont 10:3bc89ef62ce7 67 switch ((int)obj->spi) {
emilmont 10:3bc89ef62ce7 68 case SPI_0: SIM->SCGC5 |= 1 << 11; SIM->SCGC4 |= 1 << 22; break;
emilmont 10:3bc89ef62ce7 69 case SPI_1: SIM->SCGC5 |= 1 << 13; SIM->SCGC4 |= 1 << 23; break;
emilmont 10:3bc89ef62ce7 70 }
emilmont 10:3bc89ef62ce7 71
emilmont 10:3bc89ef62ce7 72 // set default format and frequency
emilmont 10:3bc89ef62ce7 73 if (ssel == NC) {
emilmont 10:3bc89ef62ce7 74 spi_format(obj, 8, 0, 0); // 8 bits, mode 0, master
emilmont 10:3bc89ef62ce7 75 } else {
emilmont 10:3bc89ef62ce7 76 spi_format(obj, 8, 0, 1); // 8 bits, mode 0, slave
emilmont 10:3bc89ef62ce7 77 }
emilmont 10:3bc89ef62ce7 78 spi_frequency(obj, 1000000);
emilmont 10:3bc89ef62ce7 79
emilmont 10:3bc89ef62ce7 80 // enable SPI
emilmont 10:3bc89ef62ce7 81 obj->spi->C1 |= SPI_C1_SPE_MASK;
emilmont 10:3bc89ef62ce7 82
emilmont 10:3bc89ef62ce7 83 // pin out the spi pins
emilmont 10:3bc89ef62ce7 84 pinmap_pinout(mosi, PinMap_SPI_MOSI);
emilmont 10:3bc89ef62ce7 85 pinmap_pinout(miso, PinMap_SPI_MISO);
emilmont 10:3bc89ef62ce7 86 pinmap_pinout(sclk, PinMap_SPI_SCLK);
emilmont 10:3bc89ef62ce7 87 if (ssel != NC) {
emilmont 10:3bc89ef62ce7 88 pinmap_pinout(ssel, PinMap_SPI_SSEL);
emilmont 10:3bc89ef62ce7 89 }
emilmont 10:3bc89ef62ce7 90 }
emilmont 10:3bc89ef62ce7 91
emilmont 10:3bc89ef62ce7 92 void spi_free(spi_t *obj) {
emilmont 10:3bc89ef62ce7 93 // [TODO]
emilmont 10:3bc89ef62ce7 94 }
emilmont 10:3bc89ef62ce7 95 void spi_format(spi_t *obj, int bits, int mode, int slave) {
emilmont 10:3bc89ef62ce7 96 if (bits != 8) {
emilmont 10:3bc89ef62ce7 97 error("Only 8bits SPI supported");
emilmont 10:3bc89ef62ce7 98 }
emilmont 10:3bc89ef62ce7 99
emilmont 10:3bc89ef62ce7 100 if ((mode < 0) || (mode > 3)) {
emilmont 10:3bc89ef62ce7 101 error("SPI mode unsupported");
emilmont 10:3bc89ef62ce7 102 }
emilmont 10:3bc89ef62ce7 103
emilmont 10:3bc89ef62ce7 104 uint8_t polarity = (mode & 0x2) ? 1 : 0;
emilmont 10:3bc89ef62ce7 105 uint8_t phase = (mode & 0x1) ? 1 : 0;
emilmont 10:3bc89ef62ce7 106 uint8_t c1_data = ((!slave) << 4) | (polarity << 3) | (phase << 2);
emilmont 10:3bc89ef62ce7 107
emilmont 10:3bc89ef62ce7 108 // clear MSTR, CPOL and CPHA bits
emilmont 10:3bc89ef62ce7 109 obj->spi->C1 &= ~(0x7 << 2);
emilmont 10:3bc89ef62ce7 110
emilmont 10:3bc89ef62ce7 111 // write new value
emilmont 10:3bc89ef62ce7 112 obj->spi->C1 |= c1_data;
emilmont 10:3bc89ef62ce7 113 }
emilmont 10:3bc89ef62ce7 114
emilmont 10:3bc89ef62ce7 115 void spi_frequency(spi_t *obj, int hz) {
emilmont 10:3bc89ef62ce7 116 uint32_t error = 0;
emilmont 10:3bc89ef62ce7 117 uint32_t p_error = 0xffffffff;
emilmont 10:3bc89ef62ce7 118 uint32_t ref = 0;
emilmont 10:3bc89ef62ce7 119 uint8_t spr = 0;
emilmont 10:3bc89ef62ce7 120 uint8_t ref_spr = 0;
emilmont 10:3bc89ef62ce7 121 uint8_t ref_prescaler = 0;
emilmont 10:3bc89ef62ce7 122
emilmont 10:3bc89ef62ce7 123 // bus clk
emilmont 10:3bc89ef62ce7 124 uint32_t PCLK = 48000000u;
emilmont 10:3bc89ef62ce7 125 uint8_t prescaler = 1;
emilmont 10:3bc89ef62ce7 126 uint8_t divisor = 2;
emilmont 10:3bc89ef62ce7 127
emilmont 10:3bc89ef62ce7 128 for (prescaler = 1; prescaler <= 8; prescaler++) {
emilmont 10:3bc89ef62ce7 129 divisor = 2;
emilmont 10:3bc89ef62ce7 130 for (spr = 0; spr <= 8; spr++) {
emilmont 10:3bc89ef62ce7 131 ref = PCLK / (prescaler*divisor);
emilmont 10:3bc89ef62ce7 132 error = (ref > hz) ? ref - hz : hz - ref;
emilmont 10:3bc89ef62ce7 133 if (error < p_error) {
emilmont 10:3bc89ef62ce7 134 ref_spr = spr;
emilmont 10:3bc89ef62ce7 135 ref_prescaler = prescaler - 1;
emilmont 10:3bc89ef62ce7 136 p_error = error;
emilmont 10:3bc89ef62ce7 137 }
emilmont 10:3bc89ef62ce7 138 divisor *= 2;
emilmont 10:3bc89ef62ce7 139 }
emilmont 10:3bc89ef62ce7 140 }
emilmont 10:3bc89ef62ce7 141
emilmont 10:3bc89ef62ce7 142 // set SPPR and SPR
emilmont 10:3bc89ef62ce7 143 obj->spi->BR = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf);
emilmont 10:3bc89ef62ce7 144 }
emilmont 10:3bc89ef62ce7 145
emilmont 10:3bc89ef62ce7 146 static inline int spi_writeable(spi_t * obj) {
emilmont 10:3bc89ef62ce7 147 return (obj->spi->S & SPI_S_SPTEF_MASK) ? 1 : 0;
emilmont 10:3bc89ef62ce7 148 }
emilmont 10:3bc89ef62ce7 149
emilmont 10:3bc89ef62ce7 150 static inline int spi_readable(spi_t * obj) {
emilmont 10:3bc89ef62ce7 151 return (obj->spi->S & SPI_S_SPRF_MASK) ? 1 : 0;
emilmont 10:3bc89ef62ce7 152 }
emilmont 10:3bc89ef62ce7 153
emilmont 10:3bc89ef62ce7 154 int spi_master_write(spi_t *obj, int value) {
emilmont 10:3bc89ef62ce7 155 // wait tx buffer empty
emilmont 10:3bc89ef62ce7 156 while(!spi_writeable(obj));
emilmont 10:3bc89ef62ce7 157 obj->spi->D = (value & 0xff);
emilmont 10:3bc89ef62ce7 158
emilmont 10:3bc89ef62ce7 159 // wait rx buffer full
emilmont 10:3bc89ef62ce7 160 while (!spi_readable(obj));
emilmont 10:3bc89ef62ce7 161 return obj->spi->D & 0xff;
emilmont 10:3bc89ef62ce7 162 }
emilmont 10:3bc89ef62ce7 163
emilmont 10:3bc89ef62ce7 164 int spi_slave_receive(spi_t *obj) {
emilmont 10:3bc89ef62ce7 165 return spi_readable(obj);
emilmont 10:3bc89ef62ce7 166 }
emilmont 10:3bc89ef62ce7 167
emilmont 10:3bc89ef62ce7 168 int spi_slave_read(spi_t *obj) {
emilmont 10:3bc89ef62ce7 169 return obj->spi->D;
emilmont 10:3bc89ef62ce7 170 }
emilmont 10:3bc89ef62ce7 171
emilmont 10:3bc89ef62ce7 172 void spi_slave_write(spi_t *obj, int value) {
emilmont 10:3bc89ef62ce7 173 while (!spi_writeable(obj));
emilmont 10:3bc89ef62ce7 174 obj->spi->D = value;
emilmont 10:3bc89ef62ce7 175 }