Skip to content

Commit

Permalink
Added SmartEEPROM Support
Browse files Browse the repository at this point in the history
  • Loading branch information
TheZoc committed Mar 2, 2021
1 parent 9df711a commit c70bae9
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 2 deletions.
142 changes: 141 additions & 1 deletion mdloader_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ char first_device;
int restart_after_program;
int hex_cols;
int hex_colw;
int force_smarteeprom_config;

//SAM-BA Settings
mailbox_t initparams;
Expand Down Expand Up @@ -377,6 +378,125 @@ int test_mcu(char silent)
return 1;
}

// SmartEEPROM NVMCTRL section
int write_user_row(uint32_t* data)
{
//Read the current state of NVMCTRL.CTRLA
NVMCTRL_CTRLA_Type ctrla;
ctrla.reg = read_half_word(NVMCTRL_CTRLA);
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);

printf("Configuring SmartEEPROM... ");

//Set WMODE to Manual
ctrla.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN;
if (!write_half_word(NVMCTRL_CTRLA, ctrla.reg))
{
printf("Error setting NVMCTRL.CTRLA.WMODE to Manual.\n");
return 0;
}
slp(SLEEP_BETWEEN_WRITES);

// Set user row address
if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER))
{
printf("Error setting NVMCTRL_ADDR to NVMCTRL_USER (1).\n");
return 0;
}

// Erase page
NVMCTRL_CTRLB_Type ctrlb;
ctrlb.reg = 0;
ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_EP;
ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY;
if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg))
{
printf("Error setting NVMCTRL_CTRLB to 0x%04x (Erase page).\n", ctrlb.reg);
return 0;
}
slp(SLEEP_BETWEEN_WRITES);

// Page buffer clear
ctrlb.reg = 0;
ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_PBC;
ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY;
if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg))
{
printf("Error setting NVMCTRL_CTRLB to 0x%04x (Page buffer clear).\n", ctrlb.reg);
return 0;
}
slp(SLEEP_BETWEEN_WRITES);

// Write in the write buffer
for (int i = 0; i < 4; i++)
{
if (!write_word(NVMCTRL_USER + i * 4, data[i]))
{
printf("Error: Unable to write NVMCTRL_USER page %i.\n", i);
return 0;
}
slp(SLEEP_BETWEEN_WRITES);
}

if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER))
{
printf("Error setting NVMCTRL_ADDR to NVMCTRL_USER (2).\n");
return 0;
}
slp(SLEEP_BETWEEN_WRITES);

// Write quad word (128bits)
ctrlb.reg = 0;
ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_WQW;
ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY;
if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg))
{
printf("Error setting NVMCTRL_CTRLB to 0x%04x (Write Quad Word).\n", ctrlb.reg);
return 0;
}

printf("Success!\n");
return 1;
}

void configure_smarteeprom(void)
{
uint32_t user_row[4];
printf("user row: ");
for (int i = 0; i < 4; i++)
{
user_row[i] = read_word(NVMCTRL_USER + i * 4);
printf("0x%08x ", user_row[i]);
}
printf("\n");

NVMCTRL_USER_ROW_MAPPING1_Type* puser_row1 = (NVMCTRL_USER_ROW_MAPPING1_Type*)(&user_row[1]);

// Check current status and proceed accordingly.
if (puser_row1->bit.SBLK == 0 && puser_row1->bit.PSZ == 0)
{
printf("SmartEEPROM not configured, proceed.\n");
}
else
{
printf("SmartEEPROM already configured - SBLK: 0x%04x - PSZ: 0x%03x.\n", puser_row1->bit.SBLK, puser_row1->bit.PSZ);
if (force_smarteeprom_config)
{
printf("--forceeep enabled, proceed.\n");
}
else
{
printf("Use --forceeep to force to configure it anyway.\n");
return;
}
}

// Set SmartEEPROM Virtual Size.
puser_row1->bit.SBLK = 0x2; // 2 blocks
puser_row1->bit.PSZ = 0x1; // 8 bytes
write_user_row(user_row);
}

//Upper case any lower case characters in a string
void strlower(char *str)
{
Expand Down Expand Up @@ -490,6 +610,8 @@ void display_help(void)
printf(" -s --size size Read firmware size of <size>\n");
printf(" -D --download file Write firmware from <file> into device\n");
printf(" -t --test Test mode (download/upload writes disabled, upload outputs data to stdout, restart disabled)\n");
printf(" --smarteep Enable Smart EEPROM MCU feature\n");
printf(" --forceeep Force re-configuration of Smart EEPROM MCU feature. Requires --smarteep.\n");
printf(" --cols count Hex listing column count <count> [%i]\n", COLS);
printf(" --colw width Hex listing column width <width> [%i]\n", COLW);
printf(" --restart Restart device after successful programming\n");
Expand All @@ -498,11 +620,13 @@ void display_help(void)

#define SW_COLS 1000
#define SW_COLW 1001
#define SW_SMARTEEP 1002

//Program command line options
struct option long_options[] = {
//Flags
{ "restart", no_argument, &restart_after_program, 1 },
{ "forceeep", no_argument, &force_smarteeprom_config, 1 },
//Other
{ "verbose", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' },
Expand All @@ -515,6 +639,7 @@ struct option long_options[] = {
{ "addr", required_argument, 0, 'a' },
{ "size", required_argument, 0, 's' },
{ "test", no_argument, 0, 't' },
{ "smarteep", no_argument, 0, SW_SMARTEEP },
{ "cols", required_argument, 0, SW_COLS },
{ "colw", required_argument, 0, SW_COLW },
{ 0, 0, 0, 0 }
Expand All @@ -528,6 +653,7 @@ int main(int argc, char *argv[])
restart_after_program = 0;
hex_cols = COLS;
hex_colw = COLW;
force_smarteeprom_config = 0;

display_version();
display_copyright();
Expand Down Expand Up @@ -628,6 +754,10 @@ int main(int argc, char *argv[])
testmode = 1;
break;

case SW_SMARTEEP:
command = CMD_CONFIG_SMARTEEPROM;
break;

case SW_COLS:
hex_cols = atoi(optarg);
if (hex_cols < 1)
Expand Down Expand Up @@ -751,14 +881,24 @@ int main(int argc, char *argv[])
print_bootloader_version();
if (verbose) printf("Device ID: %08X\n", mcu->cidr);

if (command == CMD_CONFIG_SMARTEEPROM)
{
configure_smarteeprom();

if (restart_after_program)
jump_application();

goto exitProgram;
}

//Load applet
FILE *fIn;
char appletfname[128] = "";
strlower(mcu->name);

//sprintf(appletfname, "applet-flash-%s.bin", mcu->name);
sprintf(appletfname, "applet-mdflash.bin"); //make filename non-dependent upon mcu->name

printf("Applet file: %s\n", appletfname);

fIn = fopen(appletfname, "rb");
Expand Down
62 changes: 61 additions & 1 deletion mdloader_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ enum command {
CMD_DOWNLOAD,
CMD_UPLOAD,
CMD_TEST,
CMD_ABORT
CMD_ABORT,
CMD_CONFIG_SMARTEEPROM
};

extern struct option long_options[];
Expand Down Expand Up @@ -183,6 +184,65 @@ int write_data(int addr, int writesize, int data);
void list_devices(char *first);
void strupper(char *str);
void strlower(char *str);
void configure_smarteeprom(void);

// Smart EEPROM specific
#define NVMCTRL 0x41004000
#define NVMCTRL_CTRLA (NVMCTRL)
#define NVMCTRL_CTRLB (NVMCTRL + 4)
#define NVMCTRL_ADDR (NVMCTRL + 0x14)

#define NVMCTRL_CTRLA_WMODE_MAN 0x0
#define NVMCTRL_CTRLB_CMDEX_KEY 0xA5
#define NVMCTRL_CTRLB_CMD_WQW 0x4
#define NVMCTRL_CTRLB_CMD_PBC 0x15
#define NVMCTRL_CTRLB_CMD_EP 0x0

#define NVMCTRL_USER 0x00804000

#define SLEEP_BETWEEN_WRITES 200

typedef union {
struct {
uint32_t SBLK : 4; /* bit: 35:32 - Number of NVM Blocks composing a SmartEEPROM sector */
uint32_t PSZ : 3; /* bit: 38:36 - SmartEEPROM Page Size */
uint32_t RAM_ECCDIS : 1; /* bit: 39 - RAM ECC Disable */
uint32_t : 8; /* bit: 47:40 - Factory settings - do not change */
uint32_t WDT_ENABLE : 1; /* bit: 48 - WDT Enable at power-on */
uint32_t WDT_ALWAYS_ON : 1; /* bit: 49 - WDT Always-On at power-on */
uint32_t WDT_PERIOD : 4; /* bit: 53:50 - WDT Period at power-on */
uint32_t WDT_WINDOW : 4; /* bit: 57:54 - WDT Window mode time-out at power - on */
uint32_t WDT_EWOFFSET : 4; /* bit: 61:58 - WDT Early Warning Interrupt Time Offset at power - on */
uint32_t WDT_WEN : 1; /* bit: 62 - WDT Window Mode Enable at power - on */
uint32_t : 1; /* bit: 63 - Factory settings - do not change */
} bit;
uint32_t reg;
} NVMCTRL_USER_ROW_MAPPING1_Type;

typedef union {
struct {
uint16_t : 2; /* bit: 1:0 Reserved */
uint16_t AUTOWS : 1; /* bit: 2 Auto Wait State Enable */
uint16_t SUSPEN : 1; /* bit: 3 Suspend Enable */
uint16_t WMODE : 2; /* bit: 5:4 Write Mode */
uint16_t PRM : 2; /* bit: 7:6 Power Reduction Mode during Sleep */
uint16_t RWS : 4; /* bit: 11:8 NVM Read Wait States */
uint16_t AHBNS0 : 1; /* bit: 12 Force AHB0 access to NONSEQ, burst transfers are continuously rearbitrated */
uint16_t AHBNS1 : 1; /* bit: 13 Force AHB1 access to NONSEQ, burst transfers are continuously rearbitrated */
uint16_t CACHEDIS0 : 1; /* bit: 14 AHB0 Cache Disable */
uint16_t CACHEDIS1 : 1; /* bit: 15 AHB1 Cache Disable */
} bit;
uint16_t reg;
} NVMCTRL_CTRLA_Type;

typedef union {
struct {
uint16_t CMD : 7; /* bit: 6:0 Command */
uint16_t : 1; /* bit: 7 Reserved */
uint16_t CMDEX : 8; /* bit: 15:8 Command Execution */
} bit;
uint16_t reg;
} NVMCTRL_CTRLB_Type;

#endif //_MDLOADER_COMMON_H

0 comments on commit c70bae9

Please sign in to comment.