Skip to content

Add SmartEEPROM Support #62

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

Merged
merged 6 commits into from
Oct 13, 2021
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Usage: mdloader [options] ...
-s --size size Read firmware size of <size>
-D --download file Write firmware from <file> into device
-t --test Test mode (download/upload writes disabled, upload outputs data to stdout, restart disabled)
--ignore-eep Ignore differences in SmartEEPROM configuration
--cols count Hex listing column count <count> [8]
--colw width Hex listing column width <width> [4]
--restart Restart device after successful programming
Expand Down
132 changes: 131 additions & 1 deletion mdloader_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ char verbose;
char testmode;
char first_device;
int restart_after_program;
int ignore_smarteeprom_config;
int hex_cols;
int hex_colw;

Expand Down Expand Up @@ -382,6 +383,126 @@ int test_mcu(char silent)
return 1;
}

static void sleep_between_writes(void)
{
printf(".");
fflush(stdout);
slp(SLEEP_BETWEEN_WRITES);
}

// SmartEEPROM NVMCTRL section
uint8_t 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("SmartEEPROM: Configuring...");

//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;
}
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;
}
sleep_between_writes();

// 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;
}
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;
}
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;
}
sleep_between_writes();
}

if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER))
{
printf("Error: setting NVMCTRL_ADDR to NVMCTRL_USER (2).\n");
return 0;
}
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;
}
sleep_between_writes();

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

uint8_t configure_smarteeprom(void)
{
uint32_t user_row[4];
for (int i = 0; i < 4; i++)
{
user_row[i] = read_word(NVMCTRL_USER + i * 4);
}

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

if (verbose) printf("SmartEEPROM: config - SBLK: 0x%04x - PSZ: 0x%03x.\n", puser_row1->bit.SBLK, puser_row1->bit.PSZ);

if(puser_row1->bit.SBLK == SMARTEEPROM_TARGET_SBLK && puser_row1->bit.PSZ == SMARTEEPROM_TARGET_PSZ)
{
if (verbose) printf("SmartEEPROM: Configured!\n");
return 1;
}

if(ignore_smarteeprom_config)
{
printf("SmartEEPROM: Your settings do not match the recommended values - Some functionality may not work as expected!");
return 1;
}

// Set SmartEEPROM Virtual Size.
puser_row1->bit.SBLK = SMARTEEPROM_TARGET_SBLK;
puser_row1->bit.PSZ = SMARTEEPROM_TARGET_PSZ;
return write_user_row(user_row);
}

//Upper case any lower case characters in a string
void strlower(char *str)
{
Expand Down Expand Up @@ -495,6 +616,7 @@ 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(" --ignore-eep Ignore differences in SmartEEPROM configuration\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 @@ -507,7 +629,8 @@ void display_help(void)
//Program command line options
struct option long_options[] = {
//Flags
{ "restart", no_argument, &restart_after_program, 1 },
{ "restart", no_argument, &restart_after_program, 1 },
{ "ignore-eep", no_argument, &ignore_smarteeprom_config, 1 },
//Other
{ "verbose", no_argument, 0, 'v' },
{ "help", no_argument, 0, 'h' },
Expand All @@ -531,6 +654,7 @@ int main(int argc, char *argv[])
testmode = 0;
first_device = 0;
restart_after_program = 0;
ignore_smarteeprom_config = 0;
hex_cols = COLS;
hex_colw = COLW;

Expand Down Expand Up @@ -756,7 +880,13 @@ int main(int argc, char *argv[])
print_bootloader_version();
if (verbose) printf("Device ID: %08X\n", mcu->cidr);

if (!configure_smarteeprom())
{
printf("Error: Config feature failed!\n");
goto closePort;
}

//Load applet
memcpy(&appinfo, applet_data + applet_size - sizeof(appinfo_t), sizeof(appinfo_t));
if (appinfo.magic != 0x4142444D)
{
Expand Down
66 changes: 66 additions & 0 deletions mdloader_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <string.h>
#include <stdint.h>
#include <getopt.h>
#include <ctype.h>

//Atmel files
#include "./atmel/applet.h"
Expand Down Expand Up @@ -163,6 +164,7 @@ int read_byte(int addr);
int read_half_word(int addr);
int read_word(int addr);
int set_terminal_mode(void);
uint8_t configure_smarteeprom(void);

//OS specific commands
void print_com_example(void);
Expand All @@ -181,8 +183,72 @@ int filesize(char *fname);
int read_data(int addr, int readsize);
int write_data(int addr, int writesize, int data);
void list_devices(char *first);

// helpers
void strupper(char *str);
void strlower(char *str);

// 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

// Configured for 4096 bytes - DS60001507E-page 653
#define SMARTEEPROM_TARGET_SBLK 1 // 1 block
#define SMARTEEPROM_TARGET_PSZ 3 // 32 bytes

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