spi.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /* Sd2iec - SD/MMC to Commodore serial bus interface/controller
  2. Copyright (C) 2007-2010 Ingo Korb <ingo@akana.de>
  3. Inspiration and low-level SD/MMC access based on code from MMC2IEC
  4. by Lars Pontoppidan et al., see sdcard.c|h and config.h.
  5. FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; version 2 of the License only.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. spi.c: Low-level SPI routines
  17. */
  18. #include <arm/NXP/LPC17xx/LPC17xx.h>
  19. #include "bits.h"
  20. #include "config.h"
  21. #include "spi.h"
  22. #include "uart.h"
  23. void spi_preinit()
  24. {
  25. /* Set clock prescaler to 1:1 */
  26. BITBAND( LPC_SC->SSP_PCLKREG, SSP_PCLKBIT ) = 1;
  27. }
  28. void spi_init()
  29. {
  30. /* configure data format - 8 bits, SPI, CPOL=0, CPHA=0, 1 clock per bit */
  31. SSP_REGS->CR0 = ( 8 - 1 );
  32. /* set clock prescaler */
  33. SSP_REGS->CPSR = SSP_CLK_DIVISOR;
  34. /* Enable SSP */
  35. SSP_REGS->CR1 = BV( 1 );
  36. /* Enable DMA controller, little-endian mode */
  37. BITBAND( LPC_SC->PCONP, 29 ) = 1;
  38. LPC_GPDMA->DMACConfig = 1;
  39. }
  40. void spi_tx_sync()
  41. {
  42. /* Wait until TX fifo is flushed */
  43. while ( BITBAND( SSP_REGS->SR, SSP_BSY ) ) ;
  44. }
  45. void spi_tx_byte( uint8_t data )
  46. {
  47. /* Wait until TX fifo can accept data */
  48. while ( !BITBAND( SSP_REGS->SR, SSP_TNF ) ) ;
  49. /* Send byte */
  50. SSP_REGS->DR = data;
  51. }
  52. uint8_t spi_txrx_byte( uint8_t data )
  53. {
  54. /* Wait until SSP is not busy */
  55. while ( BITBAND( SSP_REGS->SR, SSP_BSY ) ) ;
  56. /* Clear RX fifo */
  57. while ( BITBAND( SSP_REGS->SR, SSP_RNE ) )
  58. {
  59. ( void ) SSP_REGS->DR;
  60. }
  61. /* Transmit a single byte */
  62. SSP_REGS->DR = data;
  63. /* Wait until answer has been received */
  64. while ( !BITBAND( SSP_REGS->SR, SSP_RNE ) ) ;
  65. return SSP_REGS->DR;
  66. }
  67. uint8_t spi_rx_byte()
  68. {
  69. /* Wait until SSP is not busy */
  70. while ( BITBAND( SSP_REGS->SR, SSP_BSY ) ) ;
  71. /* Clear RX fifo */
  72. while ( BITBAND( SSP_REGS->SR, SSP_RNE ) )
  73. {
  74. ( void ) SSP_REGS->DR;
  75. }
  76. /* Transmit a single dummy byte */
  77. SSP_REGS->DR = 0xff;
  78. /* Wait until answer has been received */
  79. while ( !BITBAND( SSP_REGS->SR, SSP_RNE ) ) ;
  80. return SSP_REGS->DR;
  81. }
  82. void spi_tx_block( const void *ptr, unsigned int length )
  83. {
  84. const uint8_t *data = ( const uint8_t * )ptr;
  85. while ( length-- )
  86. {
  87. /* Wait until TX fifo can accept data */
  88. while ( !BITBAND( SSP_REGS->SR, SSP_TNF ) ) ;
  89. SSP_REGS->DR = *data++;
  90. }
  91. }
  92. void spi_rx_block( void *ptr, unsigned int length )
  93. {
  94. uint8_t *data = ( uint8_t * )ptr;
  95. unsigned int txlen = length;
  96. /* Wait until SSP is not busy */
  97. while ( BITBAND( SSP_REGS->SR, SSP_BSY ) ) ;
  98. /* Clear RX fifo */
  99. while ( BITBAND( SSP_REGS->SR, SSP_RNE ) )
  100. {
  101. ( void ) SSP_REGS->DR;
  102. }
  103. if ( ( length & 3 ) != 0 || ( ( uint32_t )ptr & 3 ) != 0 )
  104. {
  105. /* Odd length or unaligned buffer */
  106. while ( length > 0 )
  107. {
  108. /* Wait until TX or RX FIFO are ready */
  109. while ( txlen > 0 && !BITBAND( SSP_REGS->SR, SSP_TNF ) &&
  110. !BITBAND( SSP_REGS->SR, SSP_RNE ) ) ;
  111. /* Try to receive data */
  112. while ( length > 0 && BITBAND( SSP_REGS->SR, SSP_RNE ) )
  113. {
  114. *data++ = SSP_REGS->DR;
  115. length--;
  116. }
  117. /* Send dummy data until TX full or RX ready */
  118. while ( txlen > 0 && BITBAND( SSP_REGS->SR, SSP_TNF ) && !BITBAND( SSP_REGS->SR, SSP_RNE ) )
  119. {
  120. txlen--;
  121. SSP_REGS->DR = 0xff;
  122. }
  123. }
  124. }
  125. else
  126. {
  127. /* Clear interrupt flags of DMA channels 0 */
  128. LPC_GPDMA->DMACIntTCClear = BV( 0 );
  129. LPC_GPDMA->DMACIntErrClr = BV( 0 );
  130. /* Set up RX DMA channel */
  131. SSP_DMACH->DMACCSrcAddr = ( uint32_t )&SSP_REGS->DR;
  132. SSP_DMACH->DMACCDestAddr = ( uint32_t )ptr;
  133. SSP_DMACH->DMACCLLI = 0; // no linked list
  134. SSP_DMACH->DMACCControl = length
  135. | ( 0 << 12 ) // source burst size 1 (FIXME: Check if larger possible/useful)
  136. | ( 0 << 15 ) // destination burst size 1
  137. | ( 0 << 18 ) // source transfer width 1 byte
  138. | ( 2 << 21 ) // destination transfer width 4 bytes
  139. | ( 0 << 26 ) // source address not incremented
  140. | ( 1 << 27 ) // destination address incremented
  141. ;
  142. SSP_DMACH->DMACCConfig = 1 // enable channel
  143. | ( SSP_DMAID_RX << 1 ) // data source SSP RX
  144. | ( 2 << 11 ) // transfer from peripheral to memory
  145. ;
  146. /* Enable RX FIFO DMA */
  147. SSP_REGS->DMACR = 1;
  148. /* Write <length> bytes into TX FIFO */
  149. // FIXME: Any value in doing this using DMA too?
  150. while ( txlen > 0 )
  151. {
  152. while ( txlen > 0 && BITBAND( SSP_REGS->SR, SSP_TNF ) )
  153. {
  154. txlen--;
  155. SSP_REGS->DR = 0xff;
  156. }
  157. }
  158. /* Wait until DMA channel disables itself */
  159. while ( SSP_DMACH->DMACCConfig & 1 ) ;
  160. /* Disable RX FIFO DMA */
  161. SSP_REGS->DMACR = 0;
  162. }
  163. }