spiflash.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*
  2. * Copyright (C) 2002 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*!
  34. * \file arch/avr/dev/spiflash.c
  35. * \brief AVR SPI flash support.
  36. *
  37. * \verbatim
  38. * $Id: spiflash.c 4706 2012-10-06 17:42:01Z haraldkipp $
  39. * \endverbatim
  40. */
  41. #include <string.h>
  42. #include <sys/atom.h>
  43. #include <sys/event.h>
  44. #include <sys/timer.h>
  45. #include <sys/heap.h>
  46. #include <sys/device.h>
  47. #include <dev/spiflash.h>
  48. /*!
  49. * \addtogroup xgSpiFlash
  50. */
  51. /*@{*/
  52. /*!
  53. * \brief Exchange SPI byte.
  54. */
  55. #ifdef __GNUC__
  56. static __inline uint8_t SpiByte(uint8_t c)
  57. #else
  58. static uint8_t SpiByte(uint8_t c)
  59. #endif
  60. {
  61. outb(SPDR, c);
  62. loop_until_bit_is_set(SPSR, SPIF);
  63. return inb(SPDR);
  64. }
  65. /*!
  66. * \brief Enable SPI device flash programming.
  67. *
  68. * \return 0 if device could be located, -1 otherwise.
  69. */
  70. int SpiFlashEnable(void)
  71. {
  72. uint8_t i;
  73. uint8_t rc;
  74. /*
  75. * PB0(O): SS
  76. * PB1(O): SCK
  77. * PB2(O): MOSI
  78. * PB3(I): MISO
  79. *
  80. * PB4(O): Reset target
  81. * PB5(-): Unused
  82. * PB6(-): Unused
  83. * PB7(-): Unused
  84. */
  85. /*
  86. * SCK and MOSI outputs need configuration,
  87. * even if SPI mode is enabled.
  88. */
  89. cbi(PORTB, 1);
  90. sbi(DDRB, 1);
  91. cbi(PORTB, 2);
  92. sbi(DDRB, 2);
  93. /*
  94. * Enable pull-up on MISO.
  95. */
  96. sbi(PORTB, 3);
  97. for (i = 0; i < 32; i++) {
  98. /*
  99. * Set reset low.
  100. */
  101. cbi(PORTB, 4);
  102. sbi(DDRB, 4);
  103. /*
  104. * Set slave select pin to output. Otherwise a low signal
  105. * on this pin might force us to SPI slave mode.
  106. */
  107. sbi(DDRB, 0);
  108. outb(SPCR, BV(MSTR) | BV(SPE) | BV(SPR0));
  109. /*
  110. * Try to enable programming.
  111. */
  112. SpiByte(0xAC);
  113. SpiByte(0x53);
  114. rc = SpiByte(0xFF);
  115. SpiByte(0xff);
  116. if (rc == 0x53)
  117. return 0;
  118. /*
  119. * Programming enable failed. This may be because the
  120. * target is not synchronized. A positive pulse on the
  121. * clock line should help.
  122. */
  123. outb(SPCR, 0);
  124. sbi(PORTB, 1);
  125. cbi(PORTB, 1);
  126. }
  127. return -1;
  128. }
  129. /*!
  130. * Read SPI device ID.
  131. *
  132. * \param id Three byte character array, which receives
  133. * the CPU ID.
  134. */
  135. void SpiFlashId(uint8_t * id)
  136. {
  137. uint8_t i;
  138. for (i = 0; i < 3; i++) {
  139. SpiByte(0x30);
  140. SpiByte(0x00);
  141. SpiByte(i);
  142. id[i] = SpiByte(0x00);
  143. }
  144. }
  145. /*!
  146. * \brief Write byte to the target's flash memory.
  147. *
  148. * The target must have been erased by a previous call
  149. * to SpiFlashErase().
  150. *
  151. * \param high Must be 0 to write the low byte or 8 to
  152. * write the high byte.
  153. * \param addr Word address to write to.
  154. * \param data Byte value to write.
  155. *
  156. * \return 0 on success, -1 otherwise.
  157. */
  158. int SpiFlashWriteByte(uint8_t high, uint16_t addr, uint8_t data)
  159. {
  160. uint8_t d;
  161. if (data != 0xff) {
  162. SpiByte(0x40 | high);
  163. SpiByte(addr >> 8);
  164. SpiByte(addr & 0xFF);
  165. SpiByte(data);
  166. /*
  167. * During programming a value of 0x7F appears at the memory location.
  168. * If we are programming this value, we delay execution by 10 ms.
  169. * Otherwise we poll the memory location until we read back the
  170. * programmed value.
  171. */
  172. if (data == 0x7f)
  173. NutDelay(10);
  174. else {
  175. for (d = 0; d < 255; d++) {
  176. /*
  177. * Read program flash byte.
  178. */
  179. SpiByte(0x20 | high);
  180. SpiByte(addr >> 8);
  181. SpiByte(addr & 0xFF);
  182. if (SpiByte(0xFF) == data)
  183. break;
  184. }
  185. if (d == 255)
  186. return -1;
  187. }
  188. }
  189. return 0;
  190. }
  191. /*!
  192. * \brief Write word to the target's flash memory.
  193. *
  194. * \param addr Word address to write to.
  195. * \param data Word value to write.
  196. *
  197. * \return 0 on success, -1 otherwise.
  198. */
  199. int SpiFlashWriteWord(uint16_t addr, uint16_t data)
  200. {
  201. if (SpiFlashWriteByte(0, addr, data & 0xFF))
  202. return -1;
  203. if (SpiFlashWriteByte(8, addr, data >> 8))
  204. return -1;
  205. return 0;
  206. }
  207. /*!
  208. * \brief Erase target's flash memory.
  209. *
  210. * Sets all bytes on the target's flash memory to 0xFF.
  211. * In addtion all lock bits are set to 1 (unprogrammed).
  212. */
  213. void SpiFlashErase(void)
  214. {
  215. /*
  216. * Send chip erase command.
  217. */
  218. SpiByte(0xAC);
  219. SpiByte(0x80);
  220. SpiByte(0x00);
  221. SpiByte(0x00);
  222. NutDelay(25);
  223. }
  224. /*@}*/