Skip to content

Commit 0fca7d2

Browse files
committed
Added SmartEEPROM Support
1 parent 063b37e commit 0fca7d2

File tree

2 files changed

+213
-1
lines changed

2 files changed

+213
-1
lines changed

mdloader_common.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ char first_device;
3131
int restart_after_program;
3232
int hex_cols;
3333
int hex_colw;
34+
int force_smarteeprom_config;
3435

3536
//SAM-BA Settings
3637
mailbox_t initparams;
@@ -382,6 +383,137 @@ int test_mcu(char silent)
382383
return 1;
383384
}
384385

386+
// SmartEEPROM NVMCTRL section
387+
int write_user_row(uint32_t* data)
388+
{
389+
//Read the current state of NVMCTRL.CTRLA
390+
NVMCTRL_CTRLA_Type ctrla;
391+
ctrla.reg = read_half_word(NVMCTRL_CTRLA);
392+
393+
if (verbose)
394+
{
395+
printf("NVMCTRL.CTRLA: 0x%04x\n\tAUTOWS: 0x%01x\n\tSUSPEN: 0x%01x\n\tWMODE: 0x%02x\n\tPRM: 0x%02x\n\tRWS: 0x%04x\n\tAHBNS0: 0x%01x\n\tAHBNS1: 0x%01x\n\tCACHEDIS0: 0x%01x\n\tCACHEDIS1: 0x%01x\n", ctrla.reg, ctrla.bit.AUTOWS, ctrla.bit.SUSPEN, ctrla.bit.WMODE, ctrla.bit.PRM, ctrla.bit.RWS, ctrla.bit.AHBNS0, ctrla.bit.AHBNS1, ctrla.bit.CACHEDIS0, ctrla.bit.CACHEDIS1);
396+
}
397+
398+
printf("Configuring SmartEEPROM... ");
399+
400+
//Set WMODE to Manual
401+
ctrla.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN;
402+
if (!write_half_word(NVMCTRL_CTRLA, ctrla.reg))
403+
{
404+
printf("Error setting NVMCTRL.CTRLA.WMODE to Manual.\n");
405+
return 0;
406+
}
407+
slp(SLEEP_BETWEEN_WRITES);
408+
409+
// Set user row address
410+
if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER))
411+
{
412+
printf("Error setting NVMCTRL_ADDR to NVMCTRL_USER (1).\n");
413+
return 0;
414+
}
415+
416+
// Erase page
417+
NVMCTRL_CTRLB_Type ctrlb;
418+
ctrlb.reg = 0;
419+
ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_EP;
420+
ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY;
421+
if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg))
422+
{
423+
printf("Error setting NVMCTRL_CTRLB to 0x%04x (Erase page).\n", ctrlb.reg);
424+
return 0;
425+
}
426+
slp(SLEEP_BETWEEN_WRITES);
427+
428+
// Page buffer clear
429+
ctrlb.reg = 0;
430+
ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_PBC;
431+
ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY;
432+
if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg))
433+
{
434+
printf("Error setting NVMCTRL_CTRLB to 0x%04x (Page buffer clear).\n", ctrlb.reg);
435+
return 0;
436+
}
437+
slp(SLEEP_BETWEEN_WRITES);
438+
439+
// Write in the write buffer
440+
for (int i = 0; i < 4; i++)
441+
{
442+
if (!write_word(NVMCTRL_USER + i * 4, data[i]))
443+
{
444+
printf("Error: Unable to write NVMCTRL_USER page %i.\n", i);
445+
return 0;
446+
}
447+
slp(SLEEP_BETWEEN_WRITES);
448+
}
449+
450+
if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER))
451+
{
452+
printf("Error setting NVMCTRL_ADDR to NVMCTRL_USER (2).\n");
453+
return 0;
454+
}
455+
slp(SLEEP_BETWEEN_WRITES);
456+
457+
// Write quad word (128bits)
458+
ctrlb.reg = 0;
459+
ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_WQW;
460+
ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY;
461+
if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg))
462+
{
463+
printf("Error setting NVMCTRL_CTRLB to 0x%04x (Write Quad Word).\n", ctrlb.reg);
464+
return 0;
465+
}
466+
467+
printf("Success!\n");
468+
return 1;
469+
}
470+
471+
void configure_smarteeprom(void)
472+
{
473+
uint32_t user_row[4];
474+
for (int i = 0; i < 4; i++)
475+
{
476+
user_row[i] = read_word(NVMCTRL_USER + i * 4);
477+
}
478+
479+
if (verbose)
480+
{
481+
printf("user row: ");
482+
for (int i = 0; i < 4; i++)
483+
{
484+
printf("0x%08x ", user_row[i]);
485+
}
486+
printf("\n");
487+
}
488+
489+
490+
NVMCTRL_USER_ROW_MAPPING1_Type* puser_row1 = (NVMCTRL_USER_ROW_MAPPING1_Type*)(&user_row[1]);
491+
492+
// Check current status and proceed accordingly.
493+
if (puser_row1->bit.SBLK == 0 && puser_row1->bit.PSZ == 0)
494+
{
495+
printf("SmartEEPROM not configured, proceed.\n");
496+
}
497+
else
498+
{
499+
printf("SmartEEPROM is already configured - SBLK: 0x%04x - PSZ: 0x%03x.\n", puser_row1->bit.SBLK, puser_row1->bit.PSZ);
500+
if (force_smarteeprom_config)
501+
{
502+
printf("--forceeep enabled, reconfiguring SmartEEPROM.\n");
503+
}
504+
else
505+
{
506+
printf("Use --forceeep to force SmartEEPROM reconfiguration.\n");
507+
return;
508+
}
509+
}
510+
511+
// Set SmartEEPROM Virtual Size to 1024 bytes. Specs in DS60001507E, page 653.
512+
puser_row1->bit.SBLK = 0x1; // 1 block
513+
puser_row1->bit.PSZ = 0x1; // 8 bytes
514+
write_user_row(user_row);
515+
}
516+
385517
//Upper case any lower case characters in a string
386518
void strlower(char *str)
387519
{
@@ -495,6 +627,8 @@ void display_help(void)
495627
printf(" -s --size size Read firmware size of <size>\n");
496628
printf(" -D --download file Write firmware from <file> into device\n");
497629
printf(" -t --test Test mode (download/upload writes disabled, upload outputs data to stdout, restart disabled)\n");
630+
printf(" --smarteep Enable Smart EEPROM MCU feature\n");
631+
printf(" --forceeep Force re-configuration of Smart EEPROM MCU feature. Requires --smarteep.\n");
498632
printf(" --cols count Hex listing column count <count> [%i]\n", COLS);
499633
printf(" --colw width Hex listing column width <width> [%i]\n", COLW);
500634
printf(" --restart Restart device after successful programming\n");
@@ -503,11 +637,13 @@ void display_help(void)
503637

504638
#define SW_COLS 1000
505639
#define SW_COLW 1001
640+
#define SW_SMARTEEP 1002
506641

507642
//Program command line options
508643
struct option long_options[] = {
509644
//Flags
510645
{ "restart", no_argument, &restart_after_program, 1 },
646+
{ "forceeep", no_argument, &force_smarteeprom_config, 1 },
511647
//Other
512648
{ "verbose", no_argument, 0, 'v' },
513649
{ "help", no_argument, 0, 'h' },
@@ -520,6 +656,7 @@ struct option long_options[] = {
520656
{ "addr", required_argument, 0, 'a' },
521657
{ "size", required_argument, 0, 's' },
522658
{ "test", no_argument, 0, 't' },
659+
{ "smarteep", no_argument, 0, SW_SMARTEEP },
523660
{ "cols", required_argument, 0, SW_COLS },
524661
{ "colw", required_argument, 0, SW_COLW },
525662
{ 0, 0, 0, 0 }
@@ -533,6 +670,7 @@ int main(int argc, char *argv[])
533670
restart_after_program = 0;
534671
hex_cols = COLS;
535672
hex_colw = COLW;
673+
force_smarteeprom_config = 0;
536674

537675
display_version();
538676
display_copyright();
@@ -633,6 +771,10 @@ int main(int argc, char *argv[])
633771
testmode = 1;
634772
break;
635773

774+
case SW_SMARTEEP:
775+
command = CMD_CONFIG_SMARTEEPROM;
776+
break;
777+
636778
case SW_COLS:
637779
hex_cols = atoi(optarg);
638780
if (hex_cols < 1)
@@ -754,7 +896,17 @@ int main(int argc, char *argv[])
754896
printf("Found MCU: %s\n", mcu->name);
755897

756898
print_bootloader_version();
899+
757900
if (verbose) printf("Device ID: %08X\n", mcu->cidr);
901+
if (command == CMD_CONFIG_SMARTEEPROM)
902+
{
903+
configure_smarteeprom();
904+
905+
if (restart_after_program)
906+
jump_application();
907+
908+
goto exitProgram;
909+
}
758910

759911

760912
memcpy(&appinfo, applet_data + applet_size - sizeof(appinfo_t), sizeof(appinfo_t));

mdloader_common.h

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ enum command {
144144
CMD_DOWNLOAD,
145145
CMD_UPLOAD,
146146
CMD_TEST,
147-
CMD_ABORT
147+
CMD_ABORT,
148+
CMD_CONFIG_SMARTEEPROM
148149
};
149150

150151
extern struct option long_options[];
@@ -183,6 +184,65 @@ int write_data(int addr, int writesize, int data);
183184
void list_devices(char *first);
184185
void strupper(char *str);
185186
void strlower(char *str);
187+
void configure_smarteeprom(void);
188+
189+
// Smart EEPROM specific
190+
#define NVMCTRL 0x41004000
191+
#define NVMCTRL_CTRLA (NVMCTRL)
192+
#define NVMCTRL_CTRLB (NVMCTRL + 4)
193+
#define NVMCTRL_ADDR (NVMCTRL + 0x14)
194+
195+
#define NVMCTRL_CTRLA_WMODE_MAN 0x0
196+
#define NVMCTRL_CTRLB_CMDEX_KEY 0xA5
197+
#define NVMCTRL_CTRLB_CMD_WQW 0x4
198+
#define NVMCTRL_CTRLB_CMD_PBC 0x15
199+
#define NVMCTRL_CTRLB_CMD_EP 0x0
200+
201+
#define NVMCTRL_USER 0x00804000
202+
203+
#define SLEEP_BETWEEN_WRITES 200
204+
205+
typedef union {
206+
struct {
207+
uint32_t SBLK : 4; /* bit: 35:32 - Number of NVM Blocks composing a SmartEEPROM sector */
208+
uint32_t PSZ : 3; /* bit: 38:36 - SmartEEPROM Page Size */
209+
uint32_t RAM_ECCDIS : 1; /* bit: 39 - RAM ECC Disable */
210+
uint32_t : 8; /* bit: 47:40 - Factory settings - do not change */
211+
uint32_t WDT_ENABLE : 1; /* bit: 48 - WDT Enable at power-on */
212+
uint32_t WDT_ALWAYS_ON : 1; /* bit: 49 - WDT Always-On at power-on */
213+
uint32_t WDT_PERIOD : 4; /* bit: 53:50 - WDT Period at power-on */
214+
uint32_t WDT_WINDOW : 4; /* bit: 57:54 - WDT Window mode time-out at power - on */
215+
uint32_t WDT_EWOFFSET : 4; /* bit: 61:58 - WDT Early Warning Interrupt Time Offset at power - on */
216+
uint32_t WDT_WEN : 1; /* bit: 62 - WDT Window Mode Enable at power - on */
217+
uint32_t : 1; /* bit: 63 - Factory settings - do not change */
218+
} bit;
219+
uint32_t reg;
220+
} NVMCTRL_USER_ROW_MAPPING1_Type;
221+
222+
typedef union {
223+
struct {
224+
uint16_t : 2; /* bit: 1:0 Reserved */
225+
uint16_t AUTOWS : 1; /* bit: 2 Auto Wait State Enable */
226+
uint16_t SUSPEN : 1; /* bit: 3 Suspend Enable */
227+
uint16_t WMODE : 2; /* bit: 5:4 Write Mode */
228+
uint16_t PRM : 2; /* bit: 7:6 Power Reduction Mode during Sleep */
229+
uint16_t RWS : 4; /* bit: 11:8 NVM Read Wait States */
230+
uint16_t AHBNS0 : 1; /* bit: 12 Force AHB0 access to NONSEQ, burst transfers are continuously rearbitrated */
231+
uint16_t AHBNS1 : 1; /* bit: 13 Force AHB1 access to NONSEQ, burst transfers are continuously rearbitrated */
232+
uint16_t CACHEDIS0 : 1; /* bit: 14 AHB0 Cache Disable */
233+
uint16_t CACHEDIS1 : 1; /* bit: 15 AHB1 Cache Disable */
234+
} bit;
235+
uint16_t reg;
236+
} NVMCTRL_CTRLA_Type;
237+
238+
typedef union {
239+
struct {
240+
uint16_t CMD : 7; /* bit: 6:0 Command */
241+
uint16_t : 1; /* bit: 7 Reserved */
242+
uint16_t CMDEX : 8; /* bit: 15:8 Command Execution */
243+
} bit;
244+
uint16_t reg;
245+
} NVMCTRL_CTRLB_Type;
186246

187247
#endif //_MDLOADER_COMMON_H
188248

0 commit comments

Comments
 (0)