px-fwlib 0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers generated with Doxygen 1.9.2
px_at45d.c
1/* =============================================================================
2 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7
8 Copyright (c) 2010 Pieter Conradie <https://piconomix.com>
9
10 License: MIT
11 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
12
13 Title: px_at45d.h : Adesto AT45D Serial DataFlash Driver
14 Author(s): Pieter Conradie
15 Creation Date: 2010-04-15
16
17============================================================================= */
18
19/* _____STANDARD INCLUDES____________________________________________________ */
20
21/* _____PROJECT INCLUDES_____________________________________________________ */
22#include "px_at45d.h"
23
24/* _____LOCAL DEFINITIONS____________________________________________________ */
25/// @name Read commands
26/// @{
27#define PX_AT45D_CMD_CONTINUOUS_ARRAY_READ 0xe8
28#define PX_AT45D_CMD_MAIN_MEMORY_PAGE_READ 0xd2
29#define PX_AT45D_CMD_STATUS_REGISTER_READ 0xd7
30/// @}
31
32/// @name Program and Erase commands
33/// @{
34#define PX_AT45D_CMD_BUFFER1_WRITE 0x84
35#define PX_AT45D_CMD_BUFFER2_WRITE 0x87
36
37#define PX_AT45D_CMD_BUF1_TO_MAIN_PAGE_PRG_W_ERASE 0x83
38#define PX_AT45D_CMD_BUF2_TO_MAIN_PAGE_PRG_W_ERASE 0x86
39
40#define PX_AT45D_CMD_BUF1_TO_MAIN_PAGE_PRG_WO_ERASE 0x88
41#define PX_AT45D_CMD_BUF2_TO_MAIN_PAGE_PRG_WO_ERASE 0x89
42
43#define PX_AT45D_CMD_MAIN_MEM_PROG_THROUGH_BUF1 0x82
44#define PX_AT45D_CMD_MAIN_MEM_PROG_THROUGH_BUF2 0x85
45
46#define PX_AT45D_CMD_PAGE_ERASE 0x81
47/// @}
48
49/// @name Additional commands
50/// @{
51#define PX_AT45D_CMD_MAIN_MEM_PAGE_TO_BUF1 0x53
52#define PX_AT45D_CMD_MAIN_MEM_PAGE_TO_BUF2 0x55
53/// @}
54
55#define PX_AT45D_CMD_MAIN_DEEP_PWR_DN 0xb9
56#define PX_AT45D_CMD_MAIN_RESUME_FROM_DEEP_PWR_DN 0xab
57#define PX_AT45D_CMD_MAIN_ULTRA_DEEP_PWR_DN 0x79
58
59
60/* _____MACROS_______________________________________________________________ */
61
62/* _____GLOBAL VARIABLES_____________________________________________________ */
63
64/* _____LOCAL VARIABLES______________________________________________________ */
65static bool px_at45d_ready_flag;
66static px_spi_handle_t * px_at45d_spi_handle;
67
68/* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
69
70/* _____LOCAL FUNCTIONS______________________________________________________ */
71#if ((PX_AT45D_PAGE_SIZE != 256) && (PX_AT45D_PAGE_SIZE != 264))
72#error "This driver does not work for any other page size yet. See comment!"
73/*
74 * Unfortunately this driver still needs work to cater for other page sizes.
75 *
76 * When the address is sent, the specified page value is shifted by a fixed
77 * amount, but actually the amount of shift depends on the page size (?).
78 */
79#endif
80
81static void px_at45d_tx_adr(uint16_t page, uint16_t start_byte_in_page)
82{
83 uint8_t data[3];
84
85#if PX_VAL_IS_PWR_OF_TWO(PX_AT45D_PAGE_SIZE)
86 data[0] = (uint8_t)(page >> 8) & 0xFF;
87 data[1] = (uint8_t)(page & 0xFF);
88 data[2] = (uint8_t)(start_byte_in_page & 0xFF);
89#else
90 data[0] = (page >> 7) & 0xFF;
91 data[1] = ((page << 1) | (start_byte_in_page >> 8)) & 0xFF;
92 data[2] = start_byte_in_page & 0xFF;
93#endif
94
95 px_spi_wr(px_at45d_spi_handle, data, 3, 0);
96}
97
98/* _____GLOBAL FUNCTIONS_____________________________________________________ */
100{
101 // Set flag
102 px_at45d_ready_flag = true;
103 // Save SPI slave device handle
104 px_at45d_spi_handle = handle;
105}
106
108{
109 uint8_t data[1];
110
111 data[0] = PX_AT45D_CMD_MAIN_DEEP_PWR_DN;
112 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START_AND_STOP);
113}
114
116{
117 uint8_t data[1];
118
119 data[0] = PX_AT45D_CMD_MAIN_RESUME_FROM_DEEP_PWR_DN;
120 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START_AND_STOP);
121}
122
124{
125 uint8_t data[1];
126
127 data[0] = PX_AT45D_CMD_MAIN_ULTRA_DEEP_PWR_DN;
128 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START_AND_STOP);
129}
130
132{
133 uint8_t data[1];
134
135 data[0] = 0x00;
136 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START_AND_STOP);
137}
138
139uint16_t px_at45d_rd(void * buf, px_at45d_adr_t adr, uint16_t nr_of_bytes)
140{
141 px_at45d_adr_t max_bytes_to_read;
142 uint16_t page;
143 uint16_t start_byte_in_page;
144 uint8_t data[4];
145
146 // See if specified address is out of bounds
147 if(adr > PX_AT45D_ADR_MAX)
148 {
149 return 0;
150 }
151 // See if "number of bytes to read" should be clipped
152 max_bytes_to_read = PX_AT45D_ADR_MAX - adr + 1;
153 if(nr_of_bytes > max_bytes_to_read)
154 {
155 nr_of_bytes = max_bytes_to_read;
156 }
157 // Wait until DataFlash is not busy
158 while(!px_at45d_ready()) {;}
159 // Send command
160 data[0] = PX_AT45D_CMD_CONTINUOUS_ARRAY_READ;
161 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
162 // Calculate page, offset and number of bytes remaining in page
163#if PX_VAL_IS_PWR_OF_TWO(PX_AT45D_PAGE_SIZE)
164 page = adr >> 8;
165 start_byte_in_page = adr & 0xff;
166#else
167 page = adr / PX_AT45D_PAGE_SIZE;
168 start_byte_in_page = adr % PX_AT45D_PAGE_SIZE;
169#endif
170 // Send address
171 px_at45d_tx_adr(page, start_byte_in_page);
172 // Send dont-care bits
173 data[0] = 0x00;
174 data[1] = 0x00;
175 data[2] = 0x00;
176 data[3] = 0x00;
177 px_spi_wr(px_at45d_spi_handle, data, 4, 0);
178 // Read data
179 px_spi_rd(px_at45d_spi_handle, buf, nr_of_bytes, PX_SPI_FLAG_STOP);
180
181 return nr_of_bytes;
182}
183
184void px_at45d_rd_page(void * buf, uint16_t page)
185{
186 uint8_t data[4];
187
188 // Wait until DataFlash is not busy
189 while(!px_at45d_ready()) {;}
190 // Send command
191 data[0] = PX_AT45D_CMD_MAIN_MEMORY_PAGE_READ;
192 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
193 // Send address
194 px_at45d_tx_adr(page, 0);
195 // Send dont-care bits
196 data[0] = 0x00;
197 data[1] = 0x00;
198 data[2] = 0x00;
199 data[3] = 0x00;
200 px_spi_wr(px_at45d_spi_handle, data, 4, 0);
201 // Read data
202 px_spi_rd(px_at45d_spi_handle, buf, PX_AT45D_PAGE_SIZE, PX_SPI_FLAG_STOP);
203}
204
206 uint16_t page,
207 uint16_t start_byte_in_page,
208 uint16_t nr_of_bytes)
209{
210 uint8_t data[4];
211
212 // Wait until DataFlash is not busy
213 while(!px_at45d_ready()) {;}
214 // Send command
215 data[0] = PX_AT45D_CMD_CONTINUOUS_ARRAY_READ;
216 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
217 // Send address
218 px_at45d_tx_adr(page, start_byte_in_page);
219 // Send dont-care bits
220 data[0] = 0x00;
221 data[1] = 0x00;
222 data[2] = 0x00;
223 data[3] = 0x00;
224 px_spi_wr(px_at45d_spi_handle, data, 4, 0);
225 // Read data
226 px_spi_rd(px_at45d_spi_handle, buf, nr_of_bytes, PX_SPI_FLAG_STOP);
227}
228
229void px_at45d_wr_page(const void * buf, uint16_t page)
230{
231 uint8_t data[1];
232
233 // Wait until DataFlash is not busy
234 while(!px_at45d_ready()) {;}
235 // Send command
236 data[0] = PX_AT45D_CMD_MAIN_MEM_PROG_THROUGH_BUF1;
237 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
238 // Send address
239 px_at45d_tx_adr(page, 0);
240 // Send data to be written
241 px_spi_wr(px_at45d_spi_handle, buf, PX_AT45D_PAGE_SIZE, PX_SPI_FLAG_STOP);
242 // Set flag to busy
243 px_at45d_ready_flag = false;
244}
245
246void px_at45d_wr_page_offset(const void * buf,
247 uint16_t page,
248 uint16_t start_byte_in_page,
249 uint16_t nr_of_bytes)
250{
251 uint16_t i;
252 uint8_t * buf_u8 = (uint8_t *)buf;
253 uint8_t data[3];
254
255 // Wait until DataFlash is not busy
256 while(!px_at45d_ready()) {;}
257 // Send command
258 data[0] = PX_AT45D_CMD_BUFFER1_WRITE;
259 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
260 // Send start byte in buffer
261 data[0] = 0x00;
262 data[1] = 0x00;
263 data[2] = 0x00;
264 px_spi_wr(px_at45d_spi_handle, data, 3, 0);
265 // Fill buffer with data to be written (other bytes are 0xFF to leave them unchanged)
266 for(i = 0; i < PX_AT45D_PAGE_SIZE; i++)
267 {
268 if((i >= start_byte_in_page) && (i < (start_byte_in_page + nr_of_bytes)))
269 {
270 px_spi_wr(px_at45d_spi_handle, buf_u8++, 1, 0);
271 }
272 else
273 {
274 // Leave unchanged
275 data[0] = 0xff;
276 px_spi_wr(px_at45d_spi_handle, data, 1, 0);
277 }
278 }
279 // Deselect DataFlash
280 px_spi_wr(px_at45d_spi_handle, NULL, 0, PX_SPI_FLAG_STOP);
281 // Set flag to busy
282 px_at45d_ready_flag = false;
283 // Wait until DataFlash is not busy
284 while(!px_at45d_ready()) {;}
285 // Send command
286 data[0] = PX_AT45D_CMD_BUF1_TO_MAIN_PAGE_PRG_WO_ERASE;
287 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
288 // Send address
289 px_at45d_tx_adr(page, 0);
290 // Deselect DataFlash
291 px_spi_wr(px_at45d_spi_handle, NULL, 0, PX_SPI_FLAG_STOP);
292 // Set flag to busy
293 px_at45d_ready_flag = false;
294}
295
296void px_at45d_erase(uint16_t page)
297{
298 uint8_t data[1];
299
300 // Wait until DataFlash is not busy
301 while(!px_at45d_ready()) {;}
302 // Send command
303 data[0] = PX_AT45D_CMD_PAGE_ERASE;
304 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
305 // Send address
306 px_at45d_tx_adr(page, 0);
307 // Deselect DataFlash
308 px_spi_wr(px_at45d_spi_handle, NULL, 0, PX_SPI_FLAG_STOP);
309 // Set flag to busy
310 px_at45d_ready_flag = false;
311}
312
314{
315 uint8_t data;
316
317 // If flag has already been set, then take short cut
318 if(px_at45d_ready_flag)
319 {
320 return true;
321 }
322 // Get DataFlash status
323 data = px_at45d_get_status();
324 // See if DataFlash is ready
326 {
327 // Set flag
328 px_at45d_ready_flag = true;
329 return true;
330 }
331 else
332 {
333 return false;
334 }
335}
336
338{
339 uint8_t data[1];
340
341 // Send command
342 data[0] = PX_AT45D_CMD_STATUS_REGISTER_READ;
343 px_spi_wr(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_START);
344 // Read status
345 px_spi_rd(px_at45d_spi_handle, data, 1, PX_SPI_FLAG_STOP);
346
347 return data[0];
348}
349
351{
352 uint8_t data = px_at45d_get_status();
353
355 {
356 // Page size is a power of two
357 return true;
358 }
359 else
360 {
361 // Page size is not a power of two
362 return false;
363 }
364}
365
367{
368 uint8_t data[4];
369
371 {
372 // Page size is already a power of two
373 return false;
374 }
375 // Wait until DataFlash is not busy
376 while(!px_at45d_ready()) {;}
377 // Send command
378 data[0] = 0x3d;
379 data[1] = 0x2a;
380 data[2] = 0x80;
381 data[3] = 0xa6;
382 px_spi_wr(px_at45d_spi_handle, data, 4, PX_SPI_FLAG_START_AND_STOP);
383 // Wait until DataFlash is not busy
384 while(!px_at45d_ready()) {;}
385
386 return true;
387}
void px_at45d_rd_page_offset(void *buf, uint16_t page, uint16_t start_byte_in_page, uint16_t nr_of_bytes)
Partial read of data in a page of DataFlash.
Definition: px_at45d.c:205
uint8_t px_at45d_get_status(void)
Read the status register of the DataFlash.
Definition: px_at45d.c:337
bool px_at45d_ready(void)
Check if DataFlash is ready for the next read or write access.
Definition: px_at45d.c:313
#define PX_AT45D_STATUS_READY
Ready flag.
Definition: px_at45d.h:106
void px_at45d_wr_page(const void *buf, uint16_t page)
Write a page from DataFlash.
Definition: px_at45d.c:229
uint16_t px_at45d_rd(void *buf, px_at45d_adr_t adr, uint16_t nr_of_bytes)
Read data from DataFlash.
Definition: px_at45d.c:139
void px_at45d_resume_from_deep_power_down(void)
Power up device to resume communication.
Definition: px_at45d.c:115
bool px_at45d_set_page_size_to_pwr_of_two(void)
Sets the page size of the DataFlash to a power of two.
Definition: px_at45d.c:366
#define PX_AT45D_ADR_MAX
Maximum adress.
Definition: px_at45d.h:102
void px_at45d_erase(uint16_t page)
Erase a page of DataFlash.
Definition: px_at45d.c:296
void px_at45d_deep_power_down(void)
Power down device to minimise power consumption.
Definition: px_at45d.c:107
#define PX_AT45D_STATUS_PAGE_SIZE
Page size flag.
Definition: px_at45d.h:110
void px_at45d_ultra_deep_power_down(void)
Power down device to minimise power consumption.
Definition: px_at45d.c:123
void px_at45d_wr_page_offset(const void *buf, uint16_t page, uint16_t start_byte_in_page, uint16_t nr_of_bytes)
Partial write of data in a page of DataFlash.
Definition: px_at45d.c:246
uint32_t px_at45d_adr_t
Address size can be optimized, depending on maximum size of FLASH.
Definition: px_at45d.h:125
void px_at45d_init(px_spi_handle_t *handle)
Initialise driver.
Definition: px_at45d.c:99
bool px_at45d_page_size_is_pwr_of_two(void)
Check if page size of the DataFlash is a power of two.
Definition: px_at45d.c:350
void px_at45d_rd_page(void *buf, uint16_t page)
Read a page from DataFlash.
Definition: px_at45d.c:184
void px_at45d_resume_from_ultra_deep_power_down(void)
Power up device to resume communication.
Definition: px_at45d.c:131
#define NULL
NULL pointer.
Definition: px_defs.h:49
#define PX_BIT_IS_HI(var, bit)
Test if a bit is set (1?)
Definition: px_defs.h:187
#define PX_SPI_FLAG_START_AND_STOP
Begin and finish SPI transaction.
Definition: px_spi.h:121
#define PX_SPI_FLAG_START
Begin SPI transaction (take SPI slave's Chip Select line low)
Definition: px_spi.h:117
void px_spi_wr(px_spi_handle_t *handle, const void *data, size_t nr_of_bytes, uint8_t flags)
Perform an SPI write transaction with an SPI slave.
Definition: px_spi.c:396
void px_spi_rd(px_spi_handle_t *handle, void *data, size_t nr_of_bytes, uint8_t flags)
Perform an SPI read transaction with an SPI slave.
Definition: px_spi.c:479
#define PX_SPI_FLAG_STOP
Finish SPI transaction (take SPI slave's Chip Select line high)
Definition: px_spi.h:119
Define SPI handle.
Definition: px_spi.h:126