Skip to content

Commit

Permalink
Replacing iap_function with C RAM functions
Browse files Browse the repository at this point in the history
- It's not possible to write true RAM functions in rust (yet) where
  everything inside the function must not touch flash (needed for flash
  controller operations)
- Port ASF versions of efc_perform_fcr and efc_perform_read_sequence
  * Made a bit more generic so no compiler defines so the included
    static libraries should work for any atsam4 chip that uses EEFC/EFC
- Added some examples on how to access the unique id and user signature
- Was having a lot of issues trying to run functions from ROM so this
  code has been removed (efc_perform_fcr is the equivalent RAM function
  that ASF uses)
  • Loading branch information
haata authored and john-terrell committed Dec 15, 2021
1 parent 2847826 commit d3a8697
Show file tree
Hide file tree
Showing 10 changed files with 584 additions and 57 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/c.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: C

on: [push, pull_request]

jobs:
c:
name: C Extension Build Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc-arm-none-eabi
- name: Build
run: |
c/build.bash
Binary file added bin/thumbv7em-none-eabi.a
Binary file not shown.
Binary file added bin/thumbv7em-none-eabihf.a
Binary file not shown.
19 changes: 19 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use std::env;
use std::fs;
use std::path::PathBuf;

fn main() {
let target = env::var("TARGET").unwrap();
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

if target.starts_with("thumbv") {
// Static library used for efc C functions
fs::copy(format!("bin/{}.a", target), out_dir.join("libatsam4-hal.a")).unwrap();
println!("cargo:rustc-link-lib=static=atsam4-hal");
}

let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
println!("cargo:rustc-link-search={}", out.display());

println!("cargo:rerun-if-changed=build.rs");
}
26 changes: 26 additions & 0 deletions c/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# C Extensions for atsam4-hal

In some minimal cases, it's necessary to use C in order to do things that is not currently possible in Rust.
`build.bash` will compile the C code into the necessary static libraries that can be used during the build process.
The intent is that the static libraries are checked into git so that an embedded C compiler is not needed during a normal build.


## Functions

- efc_perform_read_sequence()
* Must be run entirely from RAM as the flash controller cannot read processor instructions from flash while accessing special
regions of EEFC (Enhanced Embedded Flash Controller).
The chip will crash immediately if you attempt to read instructions from flash during this mode.
- efc_perform_fcr()
* Alternate to the IAP function that runs in RAM instead of ROM


## Re-Building

**Dependencies**
- arm-none-eabi-gcc (Arch Linux: arm-none-eabi-gcc)
- arm-none-eabi-ar (Arch Linux: arm-none-eabi-binutils)

```bash
./build.bash
```
26 changes: 26 additions & 0 deletions c/build.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash

set -euxo pipefail

# Get directory script is in
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
TOP=$(realpath "${DIR}/..")
BIN=${TOP}/bin

# Remove existing blobs because otherwise this will append object files to the old blobs
rm -f "${BIN}"/*.a

arm-none-eabi-gcc -c -march=armv7e-m "${DIR}/efc.c" -o "${BIN}/efc.o"
arm-none-eabi-ar crs "${BIN}/thumbv7em-none-eabi.a" "${BIN}/efc.o"

arm-none-eabi-gcc -c -march=armv7e-m "${DIR}/efc.c" -DHAS_FPU -o "${BIN}/efc.o"
arm-none-eabi-ar crs "${BIN}/thumbv7em-none-eabihf.a" "${BIN}/efc.o"

# Cleanup object files
rm -f "${BIN}"/*.o
119 changes: 119 additions & 0 deletions c/component_efc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* \file
*
* Copyright (c) 2012-2018 Microchip Technology Inc. and its subsidiaries.
*
* \asf_license_start
*
* \page License
*
* Subject to your compliance with these terms, you may use Microchip
* software and any derivatives exclusively with Microchip products.
* It is your responsibility to comply with third party license terms applicable
* to your use of third party software (including open source software) that
* may accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
*/

#ifndef _SAM4S_EFC_COMPONENT_
#define _SAM4S_EFC_COMPONENT_

/* IO definitions (access restrictions to peripheral registers) */
/**
\defgroup CMSIS_glob_defs CMSIS Global Defines
<strong>IO Type Qualifiers</strong> are used
\li to specify the access to peripheral variables.
\li for automatic generation of peripheral register debug information.
*/
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */

/* ============================================================================= */
/** SOFTWARE API DEFINITION FOR Embedded Flash Controller */
/* ============================================================================= */
/** \addtogroup SAM4S_EFC Embedded Flash Controller */
/*@{*/

#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
/** \brief Efc hardware registers */
typedef struct {
__IO uint32_t EEFC_FMR; /**< \brief (Efc Offset: 0x00) EEFC Flash Mode Register */
__O uint32_t EEFC_FCR; /**< \brief (Efc Offset: 0x04) EEFC Flash Command Register */
__I uint32_t EEFC_FSR; /**< \brief (Efc Offset: 0x08) EEFC Flash Status Register */
__I uint32_t EEFC_FRR; /**< \brief (Efc Offset: 0x0C) EEFC Flash Result Register */
} Efc;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- EEFC_FMR : (EFC Offset: 0x00) EEFC Flash Mode Register -------- */
#define EEFC_FMR_FRDY (0x1u << 0) /**< \brief (EEFC_FMR) Ready Interrupt Enable */
#define EEFC_FMR_FWS_Pos 8
#define EEFC_FMR_FWS_Msk (0xfu << EEFC_FMR_FWS_Pos) /**< \brief (EEFC_FMR) Flash Wait State */
#define EEFC_FMR_FWS(value) ((EEFC_FMR_FWS_Msk & ((value) << EEFC_FMR_FWS_Pos)))
#define EEFC_FMR_SCOD (0x1u << 16) /**< \brief (EEFC_FMR) Sequential Code Optimization Disable */
#define EEFC_FMR_FAM (0x1u << 24) /**< \brief (EEFC_FMR) Flash Access Mode */
#define EEFC_FMR_CLOE (0x1u << 26) /**< \brief (EEFC_FMR) Code Loop Optimization Enable */
/* -------- EEFC_FCR : (EFC Offset: 0x04) EEFC Flash Command Register -------- */
#define EEFC_FCR_FCMD_Pos 0
#define EEFC_FCR_FCMD_Msk (0xffu << EEFC_FCR_FCMD_Pos) /**< \brief (EEFC_FCR) Flash Command */
#define EEFC_FCR_FCMD_GETD (0x0u << 0) /**< \brief (EEFC_FCR) Get Flash descriptor */
#define EEFC_FCR_FCMD_WP (0x1u << 0) /**< \brief (EEFC_FCR) Write page */
#define EEFC_FCR_FCMD_WPL (0x2u << 0) /**< \brief (EEFC_FCR) Write page and lock */
#define EEFC_FCR_FCMD_EWP (0x3u << 0) /**< \brief (EEFC_FCR) Erase page and write page */
#define EEFC_FCR_FCMD_EWPL (0x4u << 0) /**< \brief (EEFC_FCR) Erase page and write page then lock */
#define EEFC_FCR_FCMD_EA (0x5u << 0) /**< \brief (EEFC_FCR) Erase all */
#define EEFC_FCR_FCMD_EPA (0x7u << 0) /**< \brief (EEFC_FCR) Erase pages */
#define EEFC_FCR_FCMD_SLB (0x8u << 0) /**< \brief (EEFC_FCR) Set lock bit */
#define EEFC_FCR_FCMD_CLB (0x9u << 0) /**< \brief (EEFC_FCR) Clear lock bit */
#define EEFC_FCR_FCMD_GLB (0xAu << 0) /**< \brief (EEFC_FCR) Get lock bit */
#define EEFC_FCR_FCMD_SGPB (0xBu << 0) /**< \brief (EEFC_FCR) Set GPNVM bit */
#define EEFC_FCR_FCMD_CGPB (0xCu << 0) /**< \brief (EEFC_FCR) Clear GPNVM bit */
#define EEFC_FCR_FCMD_GGPB (0xDu << 0) /**< \brief (EEFC_FCR) Get GPNVM bit */
#define EEFC_FCR_FCMD_STUI (0xEu << 0) /**< \brief (EEFC_FCR) Start read unique identifier */
#define EEFC_FCR_FCMD_SPUI (0xFu << 0) /**< \brief (EEFC_FCR) Stop read unique identifier */
#define EEFC_FCR_FCMD_GCALB (0x10u << 0) /**< \brief (EEFC_FCR) Get CALIB bit */
#define EEFC_FCR_FCMD_ES (0x11u << 0) /**< \brief (EEFC_FCR) Erase sector */
#define EEFC_FCR_FCMD_WUS (0x12u << 0) /**< \brief (EEFC_FCR) Write user signature */
#define EEFC_FCR_FCMD_EUS (0x13u << 0) /**< \brief (EEFC_FCR) Erase user signature */
#define EEFC_FCR_FCMD_STUS (0x14u << 0) /**< \brief (EEFC_FCR) Start read user signature */
#define EEFC_FCR_FCMD_SPUS (0x15u << 0) /**< \brief (EEFC_FCR) Stop read user signature */
#define EEFC_FCR_FARG_Pos 8
#define EEFC_FCR_FARG_Msk (0xffffu << EEFC_FCR_FARG_Pos) /**< \brief (EEFC_FCR) Flash Command Argument */
#define EEFC_FCR_FARG(value) ((EEFC_FCR_FARG_Msk & ((value) << EEFC_FCR_FARG_Pos)))
#define EEFC_FCR_FKEY_Pos 24
#define EEFC_FCR_FKEY_Msk (0xffu << EEFC_FCR_FKEY_Pos) /**< \brief (EEFC_FCR) Flash Writing Protection Key */
#define EEFC_FCR_FKEY_PASSWD (0x5Au << 24) /**< \brief (EEFC_FCR) The 0x5A value enables the command defined by the bits of the register. If the field is written with a different value, the write is not performed and no action is started. */
/* -------- EEFC_FSR : (EFC Offset: 0x08) EEFC Flash Status Register -------- */
#define EEFC_FSR_FRDY (0x1u << 0) /**< \brief (EEFC_FSR) Flash Ready Status */
#define EEFC_FSR_FCMDE (0x1u << 1) /**< \brief (EEFC_FSR) Flash Command Error Status */
#define EEFC_FSR_FLOCKE (0x1u << 2) /**< \brief (EEFC_FSR) Flash Lock Error Status */
#define EEFC_FSR_FLERR (0x1u << 3) /**< \brief (EEFC_FSR) Flash Error Status */
/* -------- EEFC_FRR : (EFC Offset: 0x0C) EEFC Flash Result Register -------- */
#define EEFC_FRR_FVALUE_Pos 0
#define EEFC_FRR_FVALUE_Msk (0xffffffffu << EEFC_FRR_FVALUE_Pos) /**< \brief (EEFC_FRR) Flash Result Value */

/*@}*/


#endif /* _SAM4S_EFC_COMPONENT_ */
140 changes: 140 additions & 0 deletions c/efc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/**
* \file
*
* \brief Enhanced Embedded Flash Controller (EEFC) driver for SAM.
*
* Copyright (c) 2011-2018 Microchip Technology Inc. and its subsidiaries.
*
* \asf_license_start
*
* \page License
*
* Subject to your compliance with these terms, you may use Microchip
* software and any derivatives exclusively with Microchip products.
* It is your responsibility to comply with third party license terms applicable
* to your use of third party software (including open source software) that
* may accompany Microchip software.
*
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
*
* \asf_license_stop
*
*/
/*
* Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
*/

#include "efc.h"

/**
* RAM Functions provided by ASF
* These functions are difficult/impossible to replicate in pure rust as you cannot have any flash accesses
* during these functions.
*
* These functions have been adapted to use a very small subset of ASF headers and be portable across
* atsam4 chips.
*/

/* Flash Writing Protection Key */
#define FWP_KEY 0x5Au

#define EEFC_FCR_FCMD(value) \
((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos)))
#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)


/**
* \brief Perform read sequence. Supported sequences are read Unique ID and
* read User Signature
*
* \param p_efc Pointer to an EFC instance.
* \param ul_cmd_st Start command to perform.
* \param ul_cmd_sp Stop command to perform.
* \param p_ul_buf Pointer to an data buffer.
* \param ul_size Buffer size.
* \param p_ul_data Address of flash region being used.
* Usually 0x00400000u (IFLASH0_ADDR or READ_BUFF_ADDR0)
*
* \return 0 if successful, otherwise returns an error code.
*/
__attribute__ ((__noinline__))
__attribute__ ((section(".data")))
uint32_t efc_perform_read_sequence(Efc *p_efc,
uint32_t ul_cmd_st, uint32_t ul_cmd_sp,
uint32_t *p_ul_buf, uint32_t ul_size, uint32_t *p_ul_data)
{
volatile uint32_t ul_status;
uint32_t ul_cnt;

if (p_ul_buf == NULL) {
return EFC_RC_INVALID;
}

p_efc->EEFC_FMR |= (0x1u << 16);

/* Send the Start Read command */
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0)
| EEFC_FCR_FCMD(ul_cmd_st);

/* Wait for the FRDY bit in the Flash Programming Status Register
* (EEFC_FSR) falls.
*/
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);

/* The data is located in the first address of the Flash
* memory mapping.
*/
for (ul_cnt = 0; ul_cnt < ul_size; ul_cnt++) {
p_ul_buf[ul_cnt] = p_ul_data[ul_cnt];
}

/* To stop the read mode */
p_efc->EEFC_FCR =
EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(0) |
EEFC_FCR_FCMD(ul_cmd_sp);

/* Wait for the FRDY bit in the Flash Programming Status Register (EEFC_FSR)
* rises.
*/
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);

p_efc->EEFC_FMR &= ~(0x1u << 16);

return EFC_RC_OK;
}

/**
* \brief Perform command.
*
* \param p_efc Pointer to an EFC instance.
* \param ul_fcr Flash command.
*
* \return The current status.
*/
__attribute__ ((__noinline__))
__attribute__ ((section(".data")))
uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr)
{
volatile uint32_t ul_status;

p_efc->EEFC_FCR = ul_fcr;
do {
ul_status = p_efc->EEFC_FSR;
} while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);

return (ul_status & EEFC_ERROR_FLAGS);
}
Loading

0 comments on commit d3a8697

Please sign in to comment.