Skip to content

Instantly share code, notes, and snippets.

@spirilis
Created September 8, 2015 00:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spirilis/1002c873cdaad4a61e60 to your computer and use it in GitHub Desktop.
Save spirilis/1002c873cdaad4a61e60 to your computer and use it in GitHub Desktop.
RX62N DataFlash R/W example library
/*
* dataflash_rx62n.c
*
* Created on: Nov 30, 2012
* Author: spirilis
*/
#include <stdint.h>
#include "iodefine.h"
#include "dataflash_rx62n.h"
/* Assumes 48MHz PCLK, does not use interrupts. */
volatile uint8_t *df_start = (void*)0x00100000UL;
void _dataflash_PE_mode();
void _dataflash_PE_exit();
uint8_t _dataflash_needs_reset();
uint8_t dataflash_init()
{
uint32_t i=0;
volatile uint32_t *fcufw_source = (volatile uint32_t *)0xFEFFE000UL, *fcuram = (volatile uint32_t *)0x007F8000UL;
volatile uint32_t *fcufw_end = (volatile uint32_t *)0xFEFFFFFFUL;
// Step 1: Enable read/write lockbits for data flash segments
FLASH.DFLRE0.WORD = 0x2DFF;
FLASH.DFLRE1.WORD = 0xD2FF;
FLASH.DFLWE0.WORD = 0x1EFF;
FLASH.DFLWE1.WORD = 0xE1FF;
// Step 2: Enter Program/Erase Mode
// Step 2a: Disable interrupts
FLASH.FAEINT.BIT.ROMAEIE = 0;
FLASH.FAEINT.BIT.CMDLKIE = 0;
FLASH.FAEINT.BIT.DFLAEIE = 0;
FLASH.FAEINT.BIT.DFLRPEIE = 0;
FLASH.FAEINT.BIT.DFLWPEIE = 0;
// Step 2b: Initialize FCU controller, write firmware
FLASH.FENTRYR.WORD = 0xAA00;
asm("nop"); asm("nop");
FLASH.FCURAME.WORD = 0xC401;
while (fcufw_source < fcufw_end)
*fcuram++ = *fcufw_source++;
// Step 2b: Reset FCU controller
FLASH.FRESETR.WORD = 0xCC01;
for (i=0; i<4000; i++) { asm("nop"); }
FLASH.FRESETR.WORD = 0xCC00;
while (!FLASH.FSTATR0.BIT.FRDY)
;
FLASH.FENTRYR.WORD = 0xAA80;
asm("nop"); asm("nop");
// Step 2c: Clear Status
if (FLASH.FSTATR0.BIT.ILGLERR) {
if (FLASH.FASTAT.BYTE != 0x10)
FLASH.FASTAT.BYTE = 0x10;
}
*df_start = 0x50; // Issue Status Clear cmd
// Step 2c: Enable master write bit
FLASH.FWEPROR.BYTE = 0x01;
// Step 2d: Check for errors before continuing
if (FLASH.FSTATR0.BYTE & 0x70 || FLASH.FSTATR1.BIT.FCUERR) {
return 0;
}
// Step 2e: Issue Peripheral Clock Notification
FLASH.PCKAR.WORD = 48;
*df_start = 0xE9;
*df_start = 0x03;
*(volatile uint16_t*)df_start = 0x0F0F;
*(volatile uint16_t*)df_start = 0x0F0F;
*(volatile uint16_t*)df_start = 0x0F0F;
*df_start = 0xD0;
// Check if Peripheral Clock Notification caused an error
while (!FLASH.FSTATR0.BIT.FRDY)
;
if (FLASH.FSTATR0.BIT.ILGLERR) {
return 0;
}
_dataflash_PE_exit();
return 1; // Data Flash and FCU fully initialized
}
void _dataflash_PE_mode()
{
// Enable Data Flash writing
FLASH.FENTRYR.WORD = 0xAA80;
asm("nop"); asm("nop");
// Enable Master Write bit
FLASH.FWEPROR.BYTE = 0x01;
/* Clear Status (note: we need FENTRYD set before we can do this, b/c we're
* writing a command to a pointer in the data flash addr space)
*/
if (FLASH.FSTATR0.BIT.ILGLERR) {
if (FLASH.FASTAT.BYTE != 0x10)
FLASH.FASTAT.BYTE = 0x10;
}
*df_start = 0x50; // Issue Status Clear cmd
}
void _dataflash_PE_exit()
{
// Disable Data Flash writing
FLASH.FENTRYR.WORD = 0xAA00;
asm("nop"); asm("nop");
// Disable Master Write bit
FLASH.FWEPROR.BYTE = 0x02;
}
uint8_t _dataflash_needs_reset()
{
return FLASH.FSTATR1.BIT.FCUERR;
}
uint8_t dataflash_is_blank(void* flashaddr)
{
_dataflash_PE_mode();
if (_dataflash_needs_reset()) {
if (!dataflash_init())
return 255;
_dataflash_PE_mode();
}
FLASH.FMODR.BIT.FRDMD = 1;
FLASH.DFLBCCNT.BIT.BCSIZE = 1;
*(volatile uint8_t *)flashaddr = 0x71;
*(volatile uint8_t *)flashaddr = 0xD0;
while (!FLASH.FSTATR0.BIT.FRDY)
;
FLASH.FMODR.BIT.FRDMD = 0;
if (FLASH.FSTATR0.BIT.ILGLERR) {
_dataflash_PE_exit();
return 255;
}
_dataflash_PE_exit();
if (FLASH.DFLBCSTAT.BIT.BCST) {
return 0;
}
return 1;
}
uint8_t dataflash_erase(void* flashaddr)
{
_dataflash_PE_mode();
if (_dataflash_needs_reset()) {
if (!dataflash_init())
return 0;
_dataflash_PE_mode();
}
*(volatile uint8_t *)flashaddr = 0x20;
*(volatile uint8_t *)flashaddr = 0xD0;
while (!FLASH.FSTATR0.BIT.FRDY)
;
if (FLASH.FSTATR0.BIT.ILGLERR || FLASH.FSTATR0.BIT.ERSERR) {
_dataflash_PE_exit();
return 0;
}
_dataflash_PE_exit();
return 1;
}
uint8_t dataflash_write(void* flashaddr, void* buffer, uint8_t bytes)
{
uint16_t i;
volatile uint8_t *fa = (volatile uint8_t *)flashaddr;
uint8_t *bytebuf = (uint8_t *)buffer;
if (bytes < 1 || bytes > 128 || bytes % 2 != 0)
return 0; // Not supporting >128 byte writes yet, maybe work on that later
if (bytes < 9 && (fa-df_start) % 8 != 0)
return 0; // Only write on properly aligned boundaries please...
if (bytes > 8 && (fa-df_start) % 128 != 0)
return 0; // Ditto (but for 128-byte writes)...
_dataflash_PE_mode();
if (_dataflash_needs_reset()) {
if (!dataflash_init())
return 0;
_dataflash_PE_mode();
}
if (bytes > 8) { // 128-byte page mode
*fa = 0xE8;
*fa = 0x40; // 128-bytes
for (i=0; i<128; i+=2) {
if (bytes) {
*(volatile uint16_t *)fa = (uint16_t) (bytebuf[i] | (bytebuf[i+1] << 8));
bytes -= 2;
} else
*(volatile uint16_t *)fa = 0x0000;
}
*fa = 0xD0;
} else {
*fa = 0xE8;
*fa = 0x04; // 8-bytes
for (i=0; i<8; i+=2) {
if (bytes) {
*(volatile uint16_t *)fa = (uint16_t) (bytebuf[i] | (bytebuf[i+1] << 8));
bytes -= 2;
} else
*(volatile uint16_t *)fa = 0x0000;
}
*fa = 0xD0;
}
while (!FLASH.FSTATR0.BIT.FRDY)
;
if (FLASH.FSTATR0.BIT.ILGLERR || FLASH.FSTATR0.BIT.PRGERR) {
_dataflash_PE_exit();
return 0;
}
_dataflash_PE_exit();
return 1;
}
/*
* dataflash_rx62n.h
*
* Created on: Nov 30, 2012
* Author: spirilis
*/
#ifndef DATAFLASH_RX62N_H_
#define DATAFLASH_RX62N_H_
#include <stdint.h>
uint8_t dataflash_init();
uint8_t dataflash_is_blank(void *);
uint8_t dataflash_erase(void *);
uint8_t dataflash_write(void *, void *, uint8_t);
#endif /* DATAFLASH_RX62N_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment