1 /******************************************************************************
3 * Filename: spi_flash.c
5 * Instantiation of SPI flash control routines supporting AT45DB161B
7 * Revision information:
9 * 17JAN2005 kb_admin initial creation
10 * adapted from external sources
11 * tested for basic operation only!!!
14 * No warranty, expressed or implied, is included with this software. It is
15 * provided "AS IS" and no warranty of any kind including statutory or aspects
16 * relating to merchantability or fitness for any purpose is provided. All
17 * intellectual property rights of others is maintained with the respective
18 * owners. This software is not copyrighted and is intended for reference
23 *****************************************************************************/
25 #include "at91rm9200.h"
26 #include "spi_flash.h"
29 /*********************** PRIVATE FUNCTIONS/DATA ******************************/
32 static spiCommand_t spi_command;
33 static char tx_commandBuffer[8], rx_commandBuffer[8];
36 * .KB_C_FN_DEFINITION_START
37 * void SendCommand(spiCommand_t *pCommand)
38 * Private function sends 8-bit value to the device and returns the 8-bit
40 * .KB_C_FN_DEFINITION_END
43 SendCommand(spiCommand_t *pCommand)
45 AT91PS_SPI pSPI = AT91C_BASE_SPI;
47 pSPI->SPI_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
49 pSPI->SPI_RPR = (unsigned)pCommand->rx_cmd;
50 pSPI->SPI_RCR = pCommand->rx_cmd_size;
51 pSPI->SPI_TPR = (unsigned)pCommand->tx_cmd;
52 pSPI->SPI_TCR = pCommand->tx_cmd_size;
54 pSPI->SPI_TNPR = (unsigned)pCommand->tx_data;
55 pSPI->SPI_TNCR = pCommand->tx_data_size;
56 pSPI->SPI_RNPR = (unsigned)pCommand->rx_data;
57 pSPI->SPI_RNCR = pCommand->rx_data_size;
59 pSPI->SPI_PTCR = AT91C_PDC_TXTEN | AT91C_PDC_RXTEN;
61 // wait for completion
62 while (!(pSPI->SPI_SR & AT91C_SPI_SPENDRX))
68 * .KB_C_FN_DEFINITION_START
69 * char GetFlashStatus(void)
70 * Private function to return device status.
71 * .KB_C_FN_DEFINITION_END
76 p_memset((char *)&spi_command, 0, sizeof(spi_command));
77 p_memset(tx_commandBuffer, 0, 8);
78 tx_commandBuffer[0] = STATUS_REGISTER_READ;
79 p_memset(rx_commandBuffer, 0, 8);
80 spi_command.tx_cmd = tx_commandBuffer;
81 spi_command.rx_cmd = rx_commandBuffer;
82 spi_command.rx_cmd_size = 2;
83 spi_command.tx_cmd_size = 2;
84 SendCommand(&spi_command);
85 return (rx_commandBuffer[1]);
89 * .KB_C_FN_DEFINITION_START
90 * void WaitForDeviceReady(void)
91 * Private function to poll until the device is ready for next operation.
92 * .KB_C_FN_DEFINITION_END
95 WaitForDeviceReady(void)
97 while (!(GetFlashStatus() & 0x80)) ;
100 /*************************** GLOBAL FUNCTIONS ********************************/
104 * .KB_C_FN_DEFINITION_START
105 * void SPI_ReadFlash(unsigned flash_addr, unsigned dest_addr, unsigned size)
106 * Global function to read the SPI flash device using the continuous read
108 * .KB_C_FN_DEFINITION_END
111 SPI_ReadFlash(unsigned flash_addr, char *dest_addr, unsigned size)
113 unsigned pageAddress, byteAddress;
115 // determine page address
116 pageAddress = flash_addr / FLASH_PAGE_SIZE;
118 // determine byte address
119 byteAddress = flash_addr % FLASH_PAGE_SIZE;
121 p_memset(tx_commandBuffer, 0, 8);
123 tx_commandBuffer[0] = 0xd2;
124 tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
125 tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
126 ((byteAddress >> 8) & 0x3);
127 tx_commandBuffer[3] = byteAddress & 0xFF;
128 spi_command.tx_cmd = tx_commandBuffer;
129 spi_command.tx_cmd_size = 8;
130 spi_command.tx_data_size = size;
131 spi_command.tx_data = dest_addr;
133 p_memset(rx_commandBuffer, 0, 8);
134 spi_command.rx_cmd = rx_commandBuffer;
135 spi_command.rx_cmd_size = 8;
136 spi_command.rx_data_size = size;
137 spi_command.rx_data = dest_addr;
139 tx_commandBuffer[0] = CONTINUOUS_ARRAY_READ_HF;
140 tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
141 tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
142 ((byteAddress >> 8) & 0x7);
143 tx_commandBuffer[3] = byteAddress & 0xFF;
144 spi_command.tx_cmd = tx_commandBuffer;
145 spi_command.tx_cmd_size = 5;
146 spi_command.tx_data_size = size;
147 spi_command.tx_data = dest_addr;
149 p_memset(rx_commandBuffer, 0, 8);
150 spi_command.rx_cmd = rx_commandBuffer;
151 spi_command.rx_cmd_size = 5;
152 spi_command.rx_data_size = size;
153 spi_command.rx_data = dest_addr;
156 SendCommand(&spi_command);
161 * .KB_C_FN_DEFINITION_START
162 * void SPI_WriteFlash(unsigned flash_addr, unsigned src_addr, unsigned size)
163 * Global function to program the SPI flash device. Notice the warning
164 * provided in lower-level functions regarding corruption of data in non-
165 * page aligned write operations.
166 * .KB_C_FN_DEFINITION_END
169 SPI_WriteFlash(unsigned flash_addr, char *src_addr, unsigned size)
171 unsigned pageAddress, byteAddress;
173 // determine page address
174 pageAddress = flash_addr / FLASH_PAGE_SIZE;
176 // determine byte address
177 byteAddress = flash_addr % FLASH_PAGE_SIZE;
179 p_memset(tx_commandBuffer, 0, 8);
181 tx_commandBuffer[0] = 0x82;
182 tx_commandBuffer[1] = ((pageAddress >> 6) & 0xFF);
183 tx_commandBuffer[2] = ((pageAddress << 2) & 0xFC) |
184 ((byteAddress >> 8) & 0x3);
185 tx_commandBuffer[3] = (byteAddress & 0xFF);
187 tx_commandBuffer[0] = PROGRAM_THROUGH_BUFFER;
188 tx_commandBuffer[1] = ((pageAddress >> 5) & 0xFF);
189 tx_commandBuffer[2] = ((pageAddress << 3) & 0xF8) |
190 ((byteAddress >> 8) & 0x7);
191 tx_commandBuffer[3] = (byteAddress & 0xFF);
194 p_memset(rx_commandBuffer, 0, 8);
196 spi_command.tx_cmd = tx_commandBuffer;
197 spi_command.rx_cmd = rx_commandBuffer;
198 spi_command.rx_cmd_size = 4;
199 spi_command.tx_cmd_size = 4;
201 spi_command.tx_data_size = size;
202 spi_command.tx_data = src_addr;
203 spi_command.rx_data_size = size;
204 spi_command.rx_data = src_addr;
206 SendCommand(&spi_command);
208 WaitForDeviceReady();
212 * .KB_C_FN_DEFINITION_START
213 * void SPI_InitFlash(void)
214 * Global function to initialize the SPI flash device/accessor functions.
215 * .KB_C_FN_DEFINITION_END
221 AT91PS_SPI pSPI = AT91C_BASE_SPI;
224 // enable CS0, CLK, MOSI, MISO
225 pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
226 pPio->PIO_ASR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
228 pPio->PIO_PDR = AT91C_PIO_PA3 | AT91C_PIO_PA1 | AT91C_PIO_PA0 |
231 // enable clocks to SPI
232 AT91C_BASE_PMC->PMC_PCER = 1u << AT91C_ID_SPI;
235 pSPI->SPI_CR = AT91C_SPI_SWRST;
237 pSPI->SPI_MR = (0xf << 24) | AT91C_SPI_MSTR | AT91C_SPI_MODFDIS |
240 pSPI->SPI_CSR[0] = AT91C_SPI_CPOL | (4 << 16) | (2 << 8);
241 pSPI->SPI_CR = AT91C_SPI_SPIEN;
243 pSPI->SPI_PTCR = AT91C_PDC_TXTDIS;
244 pSPI->SPI_PTCR = AT91C_PDC_RXTDIS;
253 pSPI->SPI_PTCR = AT91C_PDC_RXTEN;
254 pSPI->SPI_PTCR = AT91C_PDC_TXTEN;
256 value = pSPI->SPI_RDR;
257 value = pSPI->SPI_SR;
259 value = GetFlashStatus() & 0xFC;
261 if (value != 0xB4 && value != 0xAC)
262 printf(" Bad SPI status: 0x%x\n", value);
265 printf(" Bad SPI status: 0x%x\n", value);