PIC24 Support Libraries
pic24_flash.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 // Documentation for this file. If the \file tag isn't present,
30 // this file won't be documented.
31 /** \file
32  * FLASH memory read/write support functions. Thanks goes to David Weaver
33  * for suggestions on improving these functions.
34  */
35 
36 #include "pic24_flash.h"
37 #include "pic24_chip.h"
38 #include "pic24_unittest.h"
39 #include "pic24_util.h"
40 
41 /**
42 Write table latch with address \em u16_addrhi:u16_addrlo, data: u16_wordhi:u16_wordlo
43 \param u16_addrhi upper word of flash memory address
44 \param u16_addrlo lower word of flash memory address
45 \param u16_wordhi upper data word (only lower 8-bits are valid, upper 8-bits should be zero)
46 \param u16_wordlo lower data word
47 */
48 //doWriteLatch ;W0=TBLPAG,W1=Wn,W2=WordHi,W3=WordLo - no return values
49 void doWriteLatchFlash(uint16_t u16_addrhi, uint16_t u16_addrlo, uint16_t u16_wordhi, uint16_t u16_wordlo) {
50  TBLPAG = u16_addrhi;
51  __builtin_tblwtl(u16_addrlo,u16_wordlo); //equivalent to asm(" tblwtl W3,[W1]")
52  __builtin_tblwth(u16_addrlo,u16_wordhi); //equivalent to asm(" tblwth W2,[W1]")
53 }
54 
55 #if (defined(__PIC24E__) || defined(__dsPIC33E__))
56 //this family uses double word programming.
57 //_LoadTwoWords: ;W0=TBLPAG,W1=Wn,W2=WordHi,W3=WordLo W4=Word2Hi,W5=Word2Lo
58 //W0,W1 is not used.
59 //This is writing to 'write latches' that are at a fixed address.
60 //These contents are transfered to addresses specified by the NVMADRU/NVMADR registers which
61 //have previously been loaded
62 void LoadTwoWords(uint16_t wordhi, uint16_t wordlo, uint16_t word2hi, uint16_t word2lo) {
63  asm(" mov #0xFA,W0");
64  asm(" mov W0, TBLPAG");
65  asm(" mov #0,W1");
66  __builtin_tblwtl(0,wordlo); // asm(" tblwtl W1,[W1]");
67  __builtin_tblwth(0,wordhi); // asm(" tblwth W0,[W1++]");
68  __builtin_tblwtl(2,word2lo); // asm(" tblwtl W3,[W1]");
69  __builtin_tblwth(2,word2hi); // asm(" tblwth W2,[W1++]");
70 
71 
72 }
73 
74 void WriteMem2(uint16_t addrhi,uint16_t addrlo,uint16_t val) {
75 
76  NVMADRU = addrhi; //; Init Pointer to page to be modified
77  NVMADR = addrlo; //; Init Pointer to offset to be modified
78  NVMCON = val;
79  //__builtin_write_NVM();
80  asm("disi #06");
81  asm("mov #0x55,W0");
82  asm("mov W0, NVMKEY");
83  asm("mov #0xAA,W0");
84  asm("mov W0,NVMKEY");
85  asm("bset NVMCON,#15");
86  asm("nop");
87  asm("nop");
88 
89  asm("1: btsc NVMCON,#15"); // ;Wait for write end
90  asm(" bra 1b");
91 
92 }
93 #endif
94 
95 /**
96 Read table latch from address \em u16_addrhi:u16_addrlo
97 \param u16_addrhi upper word of flash memory address
98 \param u16_addrlo lower word of flash memory address
99 \return 24-bit data value returned in \em uint32_t type
100 */
101 //_ReadLatch: ;W0=TBLPAG,W1=Wn - data in W1:W0
102 uint32_t doReadLatchFlash(uint16_t u16_addrhi, uint16_t u16_addrlo) {
103  union32 u32_a;
104  TBLPAG = u16_addrhi;
105  u32_a.u16.ls16 = __builtin_tblrdl(u16_addrlo); //equivalent to asm(" tblrdl [W1],W0")
106  u32_a.u16.ms16 = __builtin_tblrdh(u16_addrlo); //equivalent to asm(" tblrdl [W1],W1")
107  return(u32_a.u32);
108 }
109 
110 
111 /**
112 Erases a flash page at \em u16_addrhi:u16_addrlo flash address
113 \param u16_addrhi upper word of flash memory address
114 \param u16_addrlo lower word of flash memory address
115 */
116 void doErasePageFlash (uint16_t u16_addrhi, uint16_t u16_addrlo) {
117  uint16_t u16_save_SR;
118 #if (defined(__PIC24E__) || defined(__dsPIC33E__))
119  u16_save_SR = SR;
120  //disable interrupts
121  SR = SR | 0xE0;
122  NVMCON = 0x4003;
123  NVMADRU = u16_addrhi;
124  NVMADR = u16_addrlo;
125  //start erase
126  asm("disi #06");
127  asm("mov #0x55,W0");
128  asm("mov W0, NVMKEY");
129  asm("mov #0xAA,W0");
130  asm("mov W0,NVMKEY");
131  asm("bset NVMCON,#15");
132  asm("nop");
133  asm("nop");
134  //reenable interrupts
135  SR = u16_save_SR;
136  //wait for end of erase
137  while (NVMCON & 0x8000)
138  doHeartbeat();
139 #else
140  uint16_t u16_save_TBLPAG;
141 // preserve the SR and TBLPAG registers
142  u16_save_SR = SR;
143  u16_save_TBLPAG = TBLPAG;
144 //disable interrupts
145  SR = SR | 0xE0;
146 // NVCON = flash write + erase + page erase
147  NVMCON = 0x4042;
148  TBLPAG = u16_addrhi; // select page
149 //select row
150 //equivalant to "tblwtl W1,[W1]"
151  asm("tblwtl %0,[%0]"::"r"(u16_addrlo));
152 //start erase
153  __builtin_write_NVM();
154 //reenable interrupts
155  SR = u16_save_SR;
156 //wait for end of erase
157  while (NVMCON & 0x8000)
158  doHeartbeat();
159 // restore TBLPAG
160  TBLPAG = u16_save_TBLPAG;
161 #endif
162 }
163 
164 /**
165 Write current flash row
166 */
167 
169  uint16_t u16_save_SR;
170  // save SR
171  u16_save_SR = SR;
172  // disable interrupts
173  SR = SR | 0xE0;
174  // flash write + row op
175  NVMCON = 0x4001;
176 //start write
177  __builtin_write_NVM();
178 //reenable interrupts
179  SR = u16_save_SR;
180 //wait for end of write
181  while (NVMCON & 0x8000)
182  doHeartbeat();
183 }
184 
185 /**
186 Erases a flash page at \em u32_pmemAddress, then writes \em u16_len bytes
187 from \em pu8_data to program memory.
188 \param u32_pmemAddress flash memory address, should be on a page boundary
189 \param pu8_data pointer to byte data to write
190 \param u16_len number of bytes to write, this is rounded up nearest row boundary!
191 (should be evenly divisible by 64*3). For
192 */
193 
194 void doWritePageFlash(union32 u32_pmemAddress, uint8_t* pu8_data, uint16_t u16_len) {
195  uint16_t u16_byteCnt;
196  union32 u32_a;
197 #if (defined(__PIC24E__) || defined(__dsPIC33E__))
198  union32 u32_b;
199 #endif
200  uint16_t u16_ICnt, u16_numInstructions;
201 
202  ASSERT(u16_len <= FLASH_PAGEBYTES);
203  doErasePageFlash(u32_pmemAddress.u16.ms16, u32_pmemAddress.u16.ls16); //erase page
204  //write the bytes
205  //round up to nearest row boundary
206  u16_numInstructions = u16_len/3;
207  if (u16_len % 3 != 0) u16_numInstructions++;
208  u16_numInstructions += (u16_numInstructions%FLASH_ROWSIZE);
209 #if (defined(__PIC24E__) || defined(__dsPIC33E__))
210  //double word programming for this family
211  for (u16_ICnt = 0, u16_byteCnt=0; u16_ICnt<u16_numInstructions; u16_ICnt += 2,u16_byteCnt += 6) {
212  u32_a.u8[0] = pu8_data[u16_byteCnt];
213  u32_a.u8[1] = pu8_data[u16_byteCnt+1];
214  u32_a.u8[2] = pu8_data[u16_byteCnt+2];
215  u32_a.u8[3] = 0;
216  u32_b.u8[0] = pu8_data[u16_byteCnt+3];
217  u32_b.u8[1] = pu8_data[u16_byteCnt+4];
218  u32_b.u8[2] = pu8_data[u16_byteCnt+5];
219  u32_b.u8[3] = 0;
220  LoadTwoWords(u32_a.u16.ms16,u32_a.u16.ls16,u32_b.u16.ms16,u32_b.u16.ls16);
221  WriteMem2(u32_pmemAddress.u16.ms16, u32_pmemAddress.u16.ls16,0x4001);
222  u32_pmemAddress.u32 += 4; //program memory address increments by 4
223  }
224 #else
225  for (u16_ICnt = 0, u16_byteCnt=0; u16_ICnt<u16_numInstructions; u16_ICnt += 1,u16_byteCnt += 3) {
226  u32_a.u8[0] = pu8_data[u16_byteCnt];
227  u32_a.u8[1] = pu8_data[u16_byteCnt+1];
228  u32_a.u8[2] = pu8_data[u16_byteCnt+2];
229  u32_a.u8[3] = 0;
230  doWriteLatchFlash(u32_pmemAddress.u16.ms16, u32_pmemAddress.u16.ls16,u32_a.u16.ms16,u32_a.u16.ls16);
231  if ((u16_ICnt+1)%FLASH_ROWSIZE == 0) {
232  //row boundary, write it.
233  doWriteRowFlash();
234  }
235  u32_pmemAddress.u32 += 2; //program memory address increments by 2
236  }
237 #endif
238 }
239 
240 /**
241 Reads a flash page at \em u32_pmemAddress, returns \em u16_len bytes
242 in buffer \em pu8_data
243 \param u32_pmemAddress flash memory address, should be on a page boundary
244 \param pu8_data pointer to byte data to write
245 \param u16_len number of bytes to read
246 */
247 void doReadPageFlash(union32 u32_pmemAddress, uint8_t* pu8_data, uint16_t u16_len) {
248  uint16_t u16_byteCnt;
249  union32 u32_a;
250 
251  ASSERT(u16_len <= FLASH_PAGEBYTES);
252  for (u16_byteCnt=0; u16_byteCnt<u16_len; u16_byteCnt += 3) {
253  u32_a = (union32) doReadLatchFlash(u32_pmemAddress.u16.ms16, u32_pmemAddress.u16.ls16);
254  pu8_data[u16_byteCnt] = u32_a.u8[0];
255  pu8_data[u16_byteCnt+1] = u32_a.u8[1];
256  pu8_data[u16_byteCnt+2] = u32_a.u8[2];
257  u32_pmemAddress.u32 += 2;
258  }
259 }
void doHeartbeat(void)
Definition: pic24_util.c:104
void doWriteLatchFlash(uint16_t u16_addrhi, uint16_t u16_addrlo, uint16_t u16_wordhi, uint16_t u16_wordlo)
Definition: pic24_flash.c:49
uint32_t doReadLatchFlash(uint16_t u16_addrhi, uint16_t u16_addrlo)
Definition: pic24_flash.c:102
A union type for byte, word, or dword access for 32 bit values.
Definition: pic24_unions.h:49
void doReadPageFlash(union32 u32_pmemAddress, uint8_t *pu8_data, uint16_t u16_len)
Definition: pic24_flash.c:247
void doErasePageFlash(uint16_t u16_addrhi, uint16_t u16_addrlo)
Definition: pic24_flash.c:116
#define ASSERT(test)
void doWritePageFlash(union32 u32_pmemAddress, uint8_t *pu8_data, uint16_t u16_len)
Definition: pic24_flash.c:194
unsigned char uint8_t
An abbreviation for an 8-bit unsigned integer.
Definition: dataXferImpl.h:194
void doWriteRowFlash()
Definition: pic24_flash.c:168