Skip to content

Add SmartEEPROM Support #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions mdloader_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,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 @@ -382,6 +383,137 @@ 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);

if (verbose)
{
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];
for (int i = 0; i < 4; i++)
{
user_row[i] = read_word(NVMCTRL_USER + i * 4);
}

if (verbose)
{
printf("user row: ");
for (int i = 0; i < 4; i++)
{
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 is already configured - SBLK: 0x%04x - PSZ: 0x%03x.\n", puser_row1->bit.SBLK, puser_row1->bit.PSZ);
if (force_smarteeprom_config)
{
printf("--forceeep enabled, reconfiguring SmartEEPROM.\n");
}
else
{
printf("Use --forceeep to force SmartEEPROM reconfiguration.\n");
return;
}
}

// Set SmartEEPROM Virtual Size to 1024 bytes. Specs in DS60001507E, page 653.
puser_row1->bit.SBLK = 0x1; // 1 block
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 @@ -495,6 +627,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 @@ -503,11 +637,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 @@ -520,6 +656,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 @@ -533,6 +670,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 @@ -633,6 +771,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 @@ -754,7 +896,17 @@ int main(int argc, char *argv[])
printf("Found MCU: %s\n", mcu->name);

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;
}


memcpy(&appinfo, applet_data + applet_size - sizeof(appinfo_t), sizeof(appinfo_t));
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