IAP code for Freescale platforms
Dependents: 18_PT1000 RDA5807M-FM-Radio flashaccess TF_conops_BAEFLAGIMAN ... more
K22F
Due to the default clock setup of the K22F, flash write access is there disabled. In the future I might add a workaround, but for now see: https://developer.mbed.org/questions/52738/Error-with-FreescaleIAP-code-with-K22F/
Be careful with which flash you are erasing/overwriting!
Example code:
#include "mbed.h" #include "FreescaleIAP.h" int main() { int address = flash_size() - SECTOR_SIZE; //Write in last sector int *data = (int*)address; printf("Starting\r\n"); erase_sector(address); int numbers[10] = {0, 1, 10, 100, 1000, 10000, 1000000, 10000000, 100000000, 1000000000}; program_flash(address, (char*)&numbers, 40); //10 integers of 4 bytes each: 40 bytes length printf("Resulting flash: \r\n"); for (int i = 0; i<10; i++) printf("%d\r\n", data[i]); printf("Done\r\n\n"); while (true) { } }
For an example on using this for a bootloader, check out: http://developer.mbed.org/users/Sissors/code/Bootloader_K64F/
If you want to permanently store a variable between resets, you can run into the problem of how to define the value the first time. Since the mbed drag-and-drop loader seems to issue a full-chip erase, you cannot first upload a program to set the initial value, and then switch to the regular program: The full-chip erase will also erase your initial value. One option is to use the same statements as used in the bootloader example to force it to program initial values for your variables on your memory address. This should work fine, however it is target dependent where you want to program it (generally your last sector), so it makes for a less nice example program. You can also try to detect if it is the initial run by looking at the state of the flash, by default this is all '1's. The following example does this:
#include "mbed.h" #include "FreescaleIAP.h" int main() { int address = flash_size() - SECTOR_SIZE; //Write in last sector int *data = (int*)address; //By default flash is initialized at 0xFF, this is signed -1, so now we know //the program runs for the first time. You of course need to make sure your program //never writes -1 to this variable if you use this method //Alternatively you could also do the same, but with a seperate "initial run" variable added, //so your other variables can take any value if (data[0] == -1) { printf("Initial run\r\n"); printf("Writing 42 and 42\r\n"); erase_sector(address); int newvalues[2] = {42, 42}; program_flash(address,(char*) newvalues, 8); //Two integers of 4 bytes = 8 bytes while(1); } printf("Current = %d and %d, new is %d and %d\r\n", data[0], data[1], data[0]+1, data[1]-1); int newvalues[2] = {data[0]+1, data[1]-1}; erase_sector(address); program_flash(address, (char*) newvalues, 8); while(1); }
FreescaleIAP.cpp@7:474d231b2f35, 2015-06-22 (annotated)
- Committer:
- Sissors
- Date:
- Mon Jun 22 12:15:47 2015 +0000
- Revision:
- 7:474d231b2f35
- Parent:
- 6:186db0d96fcf
- Child:
- 9:7502b2ac21c2
Only compile when Freescale device is used, this makes it possible to integrate it within code which also needs to work on other platforms.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Sissors | 0:8eef5a3e83ca | 1 | #include "FreescaleIAP.h" |
Sissors | 0:8eef5a3e83ca | 2 | |
Sissors | 7:474d231b2f35 | 3 | #ifdef TARGET_Freescale |
Sissors | 7:474d231b2f35 | 4 | |
Sissors | 2:70ade1638644 | 5 | //#define IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 6 | |
nyatla | 6:186db0d96fcf | 7 | #ifdef TARGET_K64F |
nyatla | 6:186db0d96fcf | 8 | //For K64F |
nyatla | 6:186db0d96fcf | 9 | # include "MK64F12.h" |
nyatla | 6:186db0d96fcf | 10 | # define USE_ProgramPhrase 1 |
nyatla | 6:186db0d96fcf | 11 | # define FTFA FTFE |
nyatla | 6:186db0d96fcf | 12 | # define FTFA_FSTAT_FPVIOL_MASK FTFE_FSTAT_FPVIOL_MASK |
nyatla | 6:186db0d96fcf | 13 | # define FTFA_FSTAT_ACCERR_MASK FTFE_FSTAT_ACCERR_MASK |
nyatla | 6:186db0d96fcf | 14 | # define FTFA_FSTAT_RDCOLERR_MASK FTFE_FSTAT_RDCOLERR_MASK |
nyatla | 6:186db0d96fcf | 15 | # define FTFA_FSTAT_CCIF_MASK FTFE_FSTAT_CCIF_MASK |
nyatla | 6:186db0d96fcf | 16 | # define FTFA_FSTAT_MGSTAT0_MASK FTFE_FSTAT_MGSTAT0_MASK |
nyatla | 6:186db0d96fcf | 17 | #else |
Sissors | 3:0f127a8ba79b | 18 | //Different names used on at least the K20: |
nyatla | 6:186db0d96fcf | 19 | # ifndef FTFA_FSTAT_FPVIOL_MASK |
nyatla | 6:186db0d96fcf | 20 | # define FTFA FTFL |
nyatla | 6:186db0d96fcf | 21 | # define FTFA_FSTAT_FPVIOL_MASK FTFL_FSTAT_FPVIOL_MASK |
nyatla | 6:186db0d96fcf | 22 | # define FTFA_FSTAT_ACCERR_MASK FTFL_FSTAT_ACCERR_MASK |
nyatla | 6:186db0d96fcf | 23 | # define FTFA_FSTAT_RDCOLERR_MASK FTFL_FSTAT_RDCOLERR_MASK |
nyatla | 6:186db0d96fcf | 24 | # define FTFA_FSTAT_CCIF_MASK FTFL_FSTAT_CCIF_MASK |
nyatla | 6:186db0d96fcf | 25 | # define FTFA_FSTAT_MGSTAT0_MASK FTFL_FSTAT_MGSTAT0_MASK |
nyatla | 6:186db0d96fcf | 26 | # endif |
Sissors | 3:0f127a8ba79b | 27 | #endif |
Sissors | 3:0f127a8ba79b | 28 | |
Sissors | 3:0f127a8ba79b | 29 | |
Sissors | 0:8eef5a3e83ca | 30 | enum FCMD { |
Sissors | 0:8eef5a3e83ca | 31 | Read1s = 0x01, |
Sissors | 0:8eef5a3e83ca | 32 | ProgramCheck = 0x02, |
Sissors | 0:8eef5a3e83ca | 33 | ReadResource = 0x03, |
Sissors | 0:8eef5a3e83ca | 34 | ProgramLongword = 0x06, |
nyatla | 6:186db0d96fcf | 35 | ProgramPhrase = 0x07, |
Sissors | 0:8eef5a3e83ca | 36 | EraseSector = 0x09, |
Sissors | 0:8eef5a3e83ca | 37 | Read1sBlock = 0x40, |
Sissors | 0:8eef5a3e83ca | 38 | ReadOnce = 0x41, |
Sissors | 0:8eef5a3e83ca | 39 | ProgramOnce = 0x43, |
Sissors | 0:8eef5a3e83ca | 40 | EraseAll = 0x44, |
Sissors | 0:8eef5a3e83ca | 41 | VerifyBackdoor = 0x45 |
Sissors | 0:8eef5a3e83ca | 42 | }; |
Sissors | 0:8eef5a3e83ca | 43 | |
Sissors | 0:8eef5a3e83ca | 44 | inline void run_command(void); |
Sissors | 0:8eef5a3e83ca | 45 | bool check_boundary(int address, unsigned int length); |
Sissors | 0:8eef5a3e83ca | 46 | bool check_align(int address); |
Sissors | 1:702fd2d53c17 | 47 | IAPCode verify_erased(int address, unsigned int length); |
Sissors | 0:8eef5a3e83ca | 48 | IAPCode check_error(void); |
Sissors | 3:0f127a8ba79b | 49 | IAPCode program_word(int address, char *data); |
Sissors | 0:8eef5a3e83ca | 50 | |
Sissors | 0:8eef5a3e83ca | 51 | IAPCode erase_sector(int address) { |
Sissors | 0:8eef5a3e83ca | 52 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 53 | printf("IAP: Erasing at %x\r\n", address); |
Sissors | 0:8eef5a3e83ca | 54 | #endif |
Sissors | 0:8eef5a3e83ca | 55 | if (check_align(address)) |
Sissors | 0:8eef5a3e83ca | 56 | return AlignError; |
Sissors | 0:8eef5a3e83ca | 57 | |
Sissors | 0:8eef5a3e83ca | 58 | //Setup command |
Sissors | 0:8eef5a3e83ca | 59 | FTFA->FCCOB0 = EraseSector; |
Sissors | 0:8eef5a3e83ca | 60 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
Sissors | 0:8eef5a3e83ca | 61 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
Sissors | 0:8eef5a3e83ca | 62 | FTFA->FCCOB3 = address & 0xFF; |
Sissors | 0:8eef5a3e83ca | 63 | |
Sissors | 0:8eef5a3e83ca | 64 | run_command(); |
Sissors | 0:8eef5a3e83ca | 65 | |
Sissors | 0:8eef5a3e83ca | 66 | return check_error(); |
Sissors | 0:8eef5a3e83ca | 67 | } |
Sissors | 0:8eef5a3e83ca | 68 | |
Sissors | 1:702fd2d53c17 | 69 | IAPCode program_flash(int address, char *data, unsigned int length) { |
Sissors | 1:702fd2d53c17 | 70 | #ifdef IAPDEBUG |
Sissors | 1:702fd2d53c17 | 71 | printf("IAP: Programming flash at %x with length %d\r\n", address, length); |
Sissors | 1:702fd2d53c17 | 72 | #endif |
Sissors | 1:702fd2d53c17 | 73 | if (check_align(address)) |
Sissors | 1:702fd2d53c17 | 74 | return AlignError; |
Sissors | 1:702fd2d53c17 | 75 | |
Sissors | 1:702fd2d53c17 | 76 | IAPCode eraseCheck = verify_erased(address, length); |
Sissors | 1:702fd2d53c17 | 77 | if (eraseCheck != Success) |
Sissors | 1:702fd2d53c17 | 78 | return eraseCheck; |
Sissors | 1:702fd2d53c17 | 79 | |
Sissors | 1:702fd2d53c17 | 80 | IAPCode progResult; |
nyatla | 6:186db0d96fcf | 81 | #ifdef USE_ProgramPhrase |
nyatla | 6:186db0d96fcf | 82 | for (int i = 0; i < length; i+=8) { |
nyatla | 6:186db0d96fcf | 83 | progResult = program_word(address + i, data + i); |
nyatla | 6:186db0d96fcf | 84 | if (progResult != Success) |
nyatla | 6:186db0d96fcf | 85 | return progResult; |
nyatla | 6:186db0d96fcf | 86 | } |
nyatla | 6:186db0d96fcf | 87 | #else |
Sissors | 1:702fd2d53c17 | 88 | for (int i = 0; i < length; i+=4) { |
Sissors | 1:702fd2d53c17 | 89 | progResult = program_word(address + i, data + i); |
Sissors | 1:702fd2d53c17 | 90 | if (progResult != Success) |
Sissors | 1:702fd2d53c17 | 91 | return progResult; |
Sissors | 1:702fd2d53c17 | 92 | } |
nyatla | 6:186db0d96fcf | 93 | #endif |
Sissors | 1:702fd2d53c17 | 94 | return Success; |
Sissors | 1:702fd2d53c17 | 95 | } |
Sissors | 1:702fd2d53c17 | 96 | |
Sissors | 2:70ade1638644 | 97 | uint32_t flash_size(void) { |
Sissors | 2:70ade1638644 | 98 | uint32_t retval = (SIM->FCFG2 & 0x7F000000u) >> (24-13); |
Sissors | 2:70ade1638644 | 99 | if (SIM->FCFG2 & (1<<23)) //Possible second flash bank |
Sissors | 2:70ade1638644 | 100 | retval += (SIM->FCFG2 & 0x007F0000u) >> (16-13); |
Sissors | 2:70ade1638644 | 101 | return retval; |
Sissors | 2:70ade1638644 | 102 | } |
Sissors | 2:70ade1638644 | 103 | |
Sissors | 0:8eef5a3e83ca | 104 | IAPCode program_word(int address, char *data) { |
Sissors | 0:8eef5a3e83ca | 105 | #ifdef IAPDEBUG |
nyatla | 6:186db0d96fcf | 106 | #ifdef USE_ProgramPhrase |
nyatla | 6:186db0d96fcf | 107 | printf("IAP: Programming word at %x, %d - %d - %d - %d - %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); |
nyatla | 6:186db0d96fcf | 108 | #else |
Sissors | 0:8eef5a3e83ca | 109 | printf("IAP: Programming word at %x, %d - %d - %d - %d\r\n", address, data[0], data[1], data[2], data[3]); |
Sissors | 0:8eef5a3e83ca | 110 | #endif |
nyatla | 6:186db0d96fcf | 111 | |
nyatla | 6:186db0d96fcf | 112 | #endif |
Sissors | 0:8eef5a3e83ca | 113 | if (check_align(address)) |
Sissors | 0:8eef5a3e83ca | 114 | return AlignError; |
nyatla | 6:186db0d96fcf | 115 | #ifdef USE_ProgramPhrase |
nyatla | 6:186db0d96fcf | 116 | FTFA->FCCOB0 = ProgramPhrase; |
nyatla | 6:186db0d96fcf | 117 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
nyatla | 6:186db0d96fcf | 118 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
nyatla | 6:186db0d96fcf | 119 | FTFA->FCCOB3 = address & 0xFF; |
nyatla | 6:186db0d96fcf | 120 | FTFA->FCCOB4 = data[3]; |
nyatla | 6:186db0d96fcf | 121 | FTFA->FCCOB5 = data[2]; |
nyatla | 6:186db0d96fcf | 122 | FTFA->FCCOB6 = data[1]; |
nyatla | 6:186db0d96fcf | 123 | FTFA->FCCOB7 = data[0]; |
nyatla | 6:186db0d96fcf | 124 | FTFA->FCCOB8 = data[7]; |
nyatla | 6:186db0d96fcf | 125 | FTFA->FCCOB9 = data[6]; |
nyatla | 6:186db0d96fcf | 126 | FTFA->FCCOBA = data[5]; |
nyatla | 6:186db0d96fcf | 127 | FTFA->FCCOBB = data[4]; |
nyatla | 6:186db0d96fcf | 128 | #else |
Sissors | 0:8eef5a3e83ca | 129 | //Setup command |
Sissors | 0:8eef5a3e83ca | 130 | FTFA->FCCOB0 = ProgramLongword; |
Sissors | 0:8eef5a3e83ca | 131 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
Sissors | 0:8eef5a3e83ca | 132 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
Sissors | 0:8eef5a3e83ca | 133 | FTFA->FCCOB3 = address & 0xFF; |
Sissors | 0:8eef5a3e83ca | 134 | FTFA->FCCOB4 = data[3]; |
Sissors | 0:8eef5a3e83ca | 135 | FTFA->FCCOB5 = data[2]; |
Sissors | 0:8eef5a3e83ca | 136 | FTFA->FCCOB6 = data[1]; |
Sissors | 0:8eef5a3e83ca | 137 | FTFA->FCCOB7 = data[0]; |
nyatla | 6:186db0d96fcf | 138 | #endif |
Sissors | 0:8eef5a3e83ca | 139 | run_command(); |
Sissors | 0:8eef5a3e83ca | 140 | |
Sissors | 0:8eef5a3e83ca | 141 | return check_error(); |
Sissors | 0:8eef5a3e83ca | 142 | } |
Sissors | 0:8eef5a3e83ca | 143 | |
Sissors | 0:8eef5a3e83ca | 144 | /* Clear possible flags which are set, run command, wait until done */ |
Sissors | 0:8eef5a3e83ca | 145 | inline void run_command(void) { |
Sissors | 0:8eef5a3e83ca | 146 | //Clear possible old errors, start command, wait until done |
Sissors | 4:59c57c566685 | 147 | __disable_irq(); //Disable IRQs, preventing IRQ routines from trying to access flash (thanks to https://mbed.org/users/mjr/) |
Sissors | 0:8eef5a3e83ca | 148 | FTFA->FSTAT = FTFA_FSTAT_FPVIOL_MASK | FTFA_FSTAT_ACCERR_MASK | FTFA_FSTAT_RDCOLERR_MASK; |
Sissors | 0:8eef5a3e83ca | 149 | FTFA->FSTAT = FTFA_FSTAT_CCIF_MASK; |
Sissors | 0:8eef5a3e83ca | 150 | while (!(FTFA->FSTAT & FTFA_FSTAT_CCIF_MASK)); |
Sissors | 4:59c57c566685 | 151 | __enable_irq(); |
Sissors | 0:8eef5a3e83ca | 152 | } |
Sissors | 0:8eef5a3e83ca | 153 | |
Sissors | 0:8eef5a3e83ca | 154 | |
Sissors | 0:8eef5a3e83ca | 155 | |
Sissors | 0:8eef5a3e83ca | 156 | /* Check if no flash boundary is violated |
Sissors | 0:8eef5a3e83ca | 157 | Returns true on violation */ |
Sissors | 0:8eef5a3e83ca | 158 | bool check_boundary(int address, unsigned int length) { |
Sissors | 2:70ade1638644 | 159 | int temp = (address+length - 1) / SECTOR_SIZE; |
Sissors | 2:70ade1638644 | 160 | address /= SECTOR_SIZE; |
Sissors | 0:8eef5a3e83ca | 161 | bool retval = (address != temp); |
Sissors | 0:8eef5a3e83ca | 162 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 163 | if (retval) |
Sissors | 0:8eef5a3e83ca | 164 | printf("IAP: Boundary violation\r\n"); |
Sissors | 0:8eef5a3e83ca | 165 | #endif |
Sissors | 0:8eef5a3e83ca | 166 | return retval; |
Sissors | 0:8eef5a3e83ca | 167 | } |
Sissors | 0:8eef5a3e83ca | 168 | |
Sissors | 0:8eef5a3e83ca | 169 | /* Check if address is correctly aligned |
Sissors | 0:8eef5a3e83ca | 170 | Returns true on violation */ |
Sissors | 0:8eef5a3e83ca | 171 | bool check_align(int address) { |
Sissors | 0:8eef5a3e83ca | 172 | bool retval = address & 0x03; |
Sissors | 0:8eef5a3e83ca | 173 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 174 | if (retval) |
Sissors | 0:8eef5a3e83ca | 175 | printf("IAP: Alignment violation\r\n"); |
Sissors | 0:8eef5a3e83ca | 176 | #endif |
Sissors | 0:8eef5a3e83ca | 177 | return retval; |
Sissors | 0:8eef5a3e83ca | 178 | } |
Sissors | 0:8eef5a3e83ca | 179 | |
Sissors | 1:702fd2d53c17 | 180 | /* Check if an area of flash memory is erased |
Sissors | 1:702fd2d53c17 | 181 | Returns error code or Success (in case of fully erased) */ |
Sissors | 1:702fd2d53c17 | 182 | IAPCode verify_erased(int address, unsigned int length) { |
Sissors | 1:702fd2d53c17 | 183 | #ifdef IAPDEBUG |
Sissors | 1:702fd2d53c17 | 184 | printf("IAP: Verify erased at %x with length %d\r\n", address, length); |
Sissors | 1:702fd2d53c17 | 185 | #endif |
Sissors | 1:702fd2d53c17 | 186 | |
Sissors | 1:702fd2d53c17 | 187 | if (check_align(address)) |
Sissors | 1:702fd2d53c17 | 188 | return AlignError; |
Sissors | 1:702fd2d53c17 | 189 | |
Sissors | 1:702fd2d53c17 | 190 | //Setup command |
Sissors | 1:702fd2d53c17 | 191 | FTFA->FCCOB0 = Read1s; |
Sissors | 1:702fd2d53c17 | 192 | FTFA->FCCOB1 = (address >> 16) & 0xFF; |
Sissors | 1:702fd2d53c17 | 193 | FTFA->FCCOB2 = (address >> 8) & 0xFF; |
Sissors | 1:702fd2d53c17 | 194 | FTFA->FCCOB3 = address & 0xFF; |
Sissors | 1:702fd2d53c17 | 195 | FTFA->FCCOB4 = (length >> 10) & 0xFF; |
Sissors | 1:702fd2d53c17 | 196 | FTFA->FCCOB5 = (length >> 2) & 0xFF; |
Sissors | 1:702fd2d53c17 | 197 | FTFA->FCCOB6 = 0; |
Sissors | 1:702fd2d53c17 | 198 | |
Sissors | 1:702fd2d53c17 | 199 | run_command(); |
Sissors | 1:702fd2d53c17 | 200 | |
Sissors | 1:702fd2d53c17 | 201 | IAPCode retval = check_error(); |
Sissors | 1:702fd2d53c17 | 202 | if (retval == RuntimeError) { |
Sissors | 1:702fd2d53c17 | 203 | #ifdef IAPDEBUG |
Sissors | 1:702fd2d53c17 | 204 | printf("IAP: Flash was not erased\r\n"); |
Sissors | 1:702fd2d53c17 | 205 | #endif |
Sissors | 1:702fd2d53c17 | 206 | return EraseError; |
Sissors | 1:702fd2d53c17 | 207 | } |
Sissors | 1:702fd2d53c17 | 208 | return retval; |
Sissors | 1:702fd2d53c17 | 209 | |
Sissors | 1:702fd2d53c17 | 210 | } |
Sissors | 1:702fd2d53c17 | 211 | |
Sissors | 1:702fd2d53c17 | 212 | /* Check if an error occured |
Sissors | 1:702fd2d53c17 | 213 | Returns error code or Success*/ |
Sissors | 0:8eef5a3e83ca | 214 | IAPCode check_error(void) { |
Sissors | 0:8eef5a3e83ca | 215 | if (FTFA->FSTAT & FTFA_FSTAT_FPVIOL_MASK) { |
Sissors | 0:8eef5a3e83ca | 216 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 217 | printf("IAP: Protection violation\r\n"); |
Sissors | 0:8eef5a3e83ca | 218 | #endif |
Sissors | 0:8eef5a3e83ca | 219 | return ProtectionError; |
Sissors | 0:8eef5a3e83ca | 220 | } |
Sissors | 0:8eef5a3e83ca | 221 | if (FTFA->FSTAT & FTFA_FSTAT_ACCERR_MASK) { |
Sissors | 0:8eef5a3e83ca | 222 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 223 | printf("IAP: Flash access error\r\n"); |
Sissors | 0:8eef5a3e83ca | 224 | #endif |
Sissors | 0:8eef5a3e83ca | 225 | return AccessError; |
Sissors | 0:8eef5a3e83ca | 226 | } |
Sissors | 0:8eef5a3e83ca | 227 | if (FTFA->FSTAT & FTFA_FSTAT_RDCOLERR_MASK) { |
Sissors | 0:8eef5a3e83ca | 228 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 229 | printf("IAP: Collision error\r\n"); |
Sissors | 0:8eef5a3e83ca | 230 | #endif |
Sissors | 0:8eef5a3e83ca | 231 | return CollisionError; |
Sissors | 0:8eef5a3e83ca | 232 | } |
Sissors | 1:702fd2d53c17 | 233 | if (FTFA->FSTAT & FTFA_FSTAT_MGSTAT0_MASK) { |
Sissors | 1:702fd2d53c17 | 234 | #ifdef IAPDEBUG |
Sissors | 1:702fd2d53c17 | 235 | printf("IAP: Runtime error\r\n"); |
Sissors | 1:702fd2d53c17 | 236 | #endif |
Sissors | 1:702fd2d53c17 | 237 | return RuntimeError; |
Sissors | 1:702fd2d53c17 | 238 | } |
Sissors | 0:8eef5a3e83ca | 239 | #ifdef IAPDEBUG |
Sissors | 0:8eef5a3e83ca | 240 | printf("IAP: No error reported\r\n"); |
Sissors | 0:8eef5a3e83ca | 241 | #endif |
Sissors | 0:8eef5a3e83ca | 242 | return Success; |
Sissors | 7:474d231b2f35 | 243 | } |
Sissors | 7:474d231b2f35 | 244 | |
Sissors | 7:474d231b2f35 | 245 | |
Sissors | 7:474d231b2f35 | 246 | #endif |