reform

MNT Reform: Open Source Portable Computer
Log (Feed) | Files | Refs (Tags) | README

ssp0.c (7259B)


      1 /**************************************************************************/
      2 /*!
      3     @file     ssp0.c
      4     @author   K. Townsend (microBuilder.eu)
      5 
      6     @section LICENSE
      7 
      8     Software License Agreement (BSD License)
      9 
     10     Copyright (c) 2012, K. Townsend (microBuilder.eu)
     11     All rights reserved.
     12 
     13     Redistribution and use in source and binary forms, with or without
     14     modification, are permitted provided that the following conditions are met:
     15     1. Redistributions of source code must retain the above copyright
     16     notice, this list of conditions and the following disclaimer.
     17     2. Redistributions in binary form must reproduce the above copyright
     18     notice, this list of conditions and the following disclaimer in the
     19     documentation and/or other materials provided with the distribution.
     20     3. Neither the name of the copyright holders nor the
     21     names of its contributors may be used to endorse or promote products
     22     derived from this software without specific prior written permission.
     23 
     24     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
     25     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     26     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     27     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
     28     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     29     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     31     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34 */
     35 /**************************************************************************/
     36 #include "projectconfig.h"
     37 
     38 #include "core/gpio/gpio.h"
     39 #include "core/ssp0/ssp0.h"
     40 
     41 /**************************************************************************/
     42 /*!
     43     Set SSP clock to slow (400 KHz)
     44 */
     45 /**************************************************************************/
     46 void ssp0ClockSlow()
     47 {
     48   /* Divide by 15 for SSPCLKDIV */
     49   LPC_SYSCON->SSP0CLKDIV = SCB_CLKDIV_DIV15;
     50 
     51   /* (PCLK / (CPSDVSR * [SCR+1])) = (4,800,000 / (2 x [5 + 1])) = 400 KHz */
     52   LPC_SSP0->CR0 = ( (7u << 0)     // Data size = 8-bit  (bits 3:0)
     53            | (0 << 4)             // Frame format = SPI (bits 5:4)
     54            #if CFG_SSP_CPOL0 == 1
     55            | (1  << 6)            // CPOL = 1           (bit 6)
     56            #else
     57            | (0  << 6)            // CPOL = 0           (bit 6)
     58            #endif
     59            #if CFG_SSP_CPHA0 == 1
     60            | (1 << 7)             // CPHA = 1           (bit 7)
     61            #else
     62            | (0 << 7)             // CPHA = 0           (bit 7)
     63            #endif
     64            | SSP0_SCR_5);         // Clock rate = 5     (bits 15:8)
     65 
     66   /* Clock prescale register must be even and at least 2 in master mode */
     67   LPC_SSP0->CPSR = 2;
     68 }
     69 
     70 /**************************************************************************/
     71 /*!
     72     Set SSP clock to fast (6.0 MHz)
     73 */
     74 /**************************************************************************/
     75 void ssp0ClockFast()
     76 {
     77   /* Divide by 1 for SSPCLKDIV */
     78   LPC_SYSCON->SSP0CLKDIV = SCB_CLKDIV_DIV1;
     79 
     80   /* (PCLK / (CPSDVSR * [SCR+1])) = (72,000,000 / (2 * [5 + 1])) = 6.0 MHz */
     81   LPC_SSP0->CR0 = ( (7u << 0)     // Data size = 8-bit  (bits 3:0)
     82            | (0 << 4)             // Frame format = SPI (bits 5:4)
     83            #if CFG_SSP_CPOL0 == 1
     84            | (1  << 6)            // CPOL = 1           (bit 6)
     85            #else
     86            | (0  << 6)            // CPOL = 0           (bit 6)
     87            #endif
     88            #if CFG_SSP_CPHA0 == 1
     89            | (1 << 7)             // CPHA = 1           (bit 7)
     90            #else
     91            | (0 << 7)             // CPHA = 0           (bit 7)
     92            #endif
     93            | SSP0_SCR_5);         // Clock rate = 5     (bits 15:8)
     94 
     95   /* Clock prescale register must be even and at least 2 in master mode */
     96   LPC_SSP0->CPSR = 2;
     97 }
     98 
     99 /**************************************************************************/
    100 /*!
    101     @brief Initialise SSP0
    102 */
    103 /**************************************************************************/
    104 void ssp0Init(void)
    105 {
    106   uint8_t i, Dummy=Dummy;
    107 
    108   /* Reset SSP */
    109   LPC_SYSCON->PRESETCTRL &= ~0x1;
    110   LPC_SYSCON->PRESETCTRL |= 0x01;
    111 
    112   /* Enable AHB clock to the SSP domain. */
    113   LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 11);
    114 
    115   /* Set P0.8 to SSP MISO0 */
    116   LPC_IOCON->PIO0_8 &= ~0x07;
    117   LPC_IOCON->PIO0_8 |= 0x01;
    118 
    119   /* Set P0.9 to SSP MOSI0 */
    120   LPC_IOCON->PIO0_9 &= ~0x07;
    121   LPC_IOCON->PIO0_9 |= 0x01;
    122 
    123   /* No LPC_IOCON->SCKLOC register on LPC11Uxx/13Uxx? */
    124   #if (CFG_SSP_SCK0_LOCATION == CFG_SSP_SCK0_1_29)
    125     /* Set 1.29 to SSP SCK0 (0.6 is often used by USB and 0.10 for SWD) */
    126     LPC_IOCON->PIO1_29 = 0x01;
    127   #elif (CFG_SSP_SCK0_LOCATION == CFG_SSP_SCK0_0_10)
    128     /* Set 0.10 to SSP SCK0 (may be required for SWD!) */
    129     LPC_IOCON->SWCLK_PIO0_10 = 0x02;
    130   #elif (CFG_SSP_SCK0_LOCATION == CFG_SSP_SCK0_0_6)
    131     /* Set 0.6 to SSP SCK0 (may be required for USB!) */
    132     LPC_IOCON->PIO0_6 = 0x02;
    133   #else
    134     #error "Invalid CFG_SSP_SCK0_LOCATION"
    135   #endif
    136 
    137   /* Set SPI clock to high-speed by default */
    138   ssp0ClockFast();
    139 
    140   /* Clear the Rx FIFO */
    141   for ( i = 0; i < SSP0_FIFOSIZE; i++ )
    142   {
    143     Dummy = LPC_SSP0->DR;
    144   }  
    145   
    146   /* Enable device and set it to slave mode, no loopback */
    147   LPC_SSP0->CR1 = SSP0_CR1_SSE_ENABLED | SSP0_CR1_MS_SLAVE | SSP0_CR1_LBM_NORMAL;
    148 }
    149 
    150 /**************************************************************************/
    151 /*!
    152     @brief Sends a block of data using SSP0
    153 
    154     @param[in]  buf
    155                 Pointer to the data buffer
    156     @param[in]  length
    157                 Block length of the data buffer
    158 */
    159 /**************************************************************************/
    160 void ssp0Send (uint8_t *buf, uint32_t length)
    161 {
    162   uint32_t i;
    163   uint8_t Dummy = Dummy;
    164 
    165   for (i = 0; i < length; i++)
    166   {
    167     /* Move on only if NOT busy and TX FIFO not full. */
    168     while ((LPC_SSP0->SR & (SSP0_SR_TNF_NOTFULL | SSP0_SR_BSY_BUSY)) != SSP0_SR_TNF_NOTFULL);
    169     LPC_SSP0->DR = *buf;
    170     buf++;
    171 
    172     while ( (LPC_SSP0->SR & (SSP0_SR_BSY_BUSY|SSP0_SR_RNE_NOTEMPTY)) != SSP0_SR_RNE_NOTEMPTY );
    173     /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
    174     on MISO. Otherwise, when sspReceive is called, previous data byte
    175     is left in the FIFO. */
    176     Dummy = LPC_SSP0->DR;
    177   }
    178 
    179   return;
    180 }
    181 
    182 /**************************************************************************/
    183 /*!
    184     @brief Receives a block of data using SSP0
    185 
    186     @param[in]  buf
    187                 Pointer to the data buffer
    188     @param[in]  length
    189                 Block length of the data buffer
    190 */
    191 /**************************************************************************/
    192 void ssp0Receive(uint8_t *buf, uint32_t length)
    193 {
    194   uint32_t i;
    195 
    196   for ( i = 0; i < length; i++ )
    197   {
    198     /* As long as the receive FIFO is not empty, data can be received. */
    199     LPC_SSP0->DR = 0xFF;
    200 
    201     /* Wait until the Busy bit is cleared */
    202     while ( (LPC_SSP0->SR & (SSP0_SR_BSY_BUSY|SSP0_SR_RNE_NOTEMPTY)) != SSP0_SR_RNE_NOTEMPTY );
    203 
    204     *buf = LPC_SSP0->DR;
    205     buf++;
    206   }
    207 
    208   return;
    209 }