Skip to content

Creating and using flash drivers

doctek edited this page Aug 5, 2011 · 8 revisions

What's all this "Flash Driver" business, anyway?

OpenOCD handles most interaction with a particular type of microcontroller in a general manner. For example, ARM Cortex M3 cores all follow the ARM standard for registers, commands, bus width, etc. OpenOCD needs to know about all of these and gets the details it needs from the ARM documentation. Any microcontroller that implements the ARM Cortex M3 core will work the same.

However there are differences among Cortex M3-based microcontrollers. These differences are mainly in the on-chip peripherals they offer and how these are configured and controlled. OpenOCD exists mainly to support development and debug of programs using these peripherals, and so OpenOCD doesn't really need to know anything about on-chip peripherals. That part is up to the programmer developing an application.

One may not think of flash memory as a "peripheral", but it is best thought of as exactly that. Each manufacturer has their own design for flash, and implements it as necessary on their own chips. This implementation is not in any way standardized by ARM. OpenOCD cannot provide a standard way to program flash since flash implementations all vary.

So OpenOCD does the next best thing: it requires only low level drivers that can support certain flash capabilities: write, erase, protect and a few others. Such a driver must be tailored to the specific needs and capabilities of a specific chip or family of chips from a given manufacturer. The purpose of this project is to guide you in producing such a driver.

OK, so what does a flash driver need to do?

To support device-specific programming, a flash driver must provide a minimal set of functions to OpenOCD. The obvious functions are read, write, and erase. Further obvious functions include protect and unprotect of the memory and control registers. Less obvious is is the function that identifies the specific microcontroller in use. (Two items, the probe function and the config file, control this.) Finally, there are a few support functions that a flash driver supplies.

How do I start?

First, you should have already downloaded and installed OpenOCD. If not, look at the Introduction page for links, but if you're not already using OpenOCD, then you really should get familiar with it before returning to this project.

Once you have OpenOCD installed, you will see a directory tree that looks more or less like the one here. There is also information on which files are of interest in creating new flash drivers.

Download the source files for this project from the repository. Use the Source tab at the top of this page. The stm32x_doc.c is a copy of an existing OpenOCD flash driver to which I have added extensive commenting explaining many details. The key data structures and functions are all explained.

The nucX1.c file is a flash driver I am developing for the Nuvoton NUC-120 chip. In it, I will document various successes, failures, and learnings as development proceeds.

Use git frequently as you develop. You'll use it at the end to create the git patch to submit to OpenOCD.

How does OpenOCD know what flash driver to use?

Unfortunately, there is no universal way to identify a microcontroller. No unique register or memory address is reserved to hold an id; there is not even a universal code defined. So this is done the old-fashioned way: the user must convey the identification to OpenOCD.

Conveyance is done by using a configuration file (surprise, surprise!). OpenOCD configuration files are typically in /usr/local/share/openocd/scripts. The specific configuration files that choose a particular microprocessor are in the targets subdirectory. Several lines are in these files, but a couple are really important:

Here's an example. This is from the file stm32.cfg found in the targets directory (as just discussed) after installing openocd. I have added explanations of some of the key sections.

# script for stm32

Here the cpu / driver name is set. Replace stm32 with your driver name when you're ready to test it.

if { [info exists CHIPNAME] } {

set _CHIPNAME $CHIPNAME

} else {

set _CHIPNAME stm32 }

[Deleted]

# Work-area is a space in RAM used for flash programming

# By default use 16kB

Probably too large - many smaller ARMs don't have this much.

if { [info exists WORKAREASIZE] } {

set _WORKAREASIZE $WORKAREASIZE

} else {

set _WORKAREASIZE 0x4000

}

[Lots Deleted (jkl)]

These last two lines associates the low level flash driver (that we will write) with the rest of OpenOCD. Without these lines, your new functions won't be available to OpenOCD.

set _FLASHNAME $_CHIPNAME.flash

flash bank $_FLASHNAME stm32x 0x08000000 0 0 0 $_TARGETNAME

When your driver is ready to test, you will create a file named [yourDriver].cfg and put it in the target directory. When you start OpenOCD, just give this config file name on the command line.

How does a driver get built into OpenOCD?

Building a version of OpenOCD with your new flash driver takes a few steps. First, the functions are placed in the flash_driver block at the end of the flash driver (myDriver.c). This is discussed in the stm32x_doc.c code.

Then, the driver name must be placed in the drivers.c file which is part of the OpenOCD package. (Have another look at the File Tree to help you find these files.) You'll quickly understand what you need to do: add an extern naming your driver, then add a pointer to the same name in the static struct flash_driver *flash_drivers[] array.

Now, modify the makefile so your new driver will be found during compilation and linking. The correct way to do this is to simply put the name of your flash driver in Makefile.am that is in src/flash/nor. Find the section starting with "NOR_DRIVERS = " and insert your file name appropriately, then run config and make as explained in the openocd INSTALL file.

However, if you don't want to do a new config, you can modify the Makefile itself. Specifically, modify Makefile in src/flash/nor (same directory that your driver and drivers.c are in). You'll insert the file name in three sections in Makefile: the "am__objects_1 =" section, the "NOR_DRIVERS = " section, and the "include ./$(DEPDIR)" section. When you look at these sections, you'll readily see the form of the name to use.

Finally, do a make from the openocd top level directory as described on the File Tree page.

How do flash drivers become part of OpenOCD?

So far I have explained how to make a new flash driver part of OpenOCD, but only for local use. Once your driver is working satisfactorily, you'll want it to become part of the official OpenOCD package. Since you've been using git during your development, it's easy to create a suitable patch to submit. The directions are in the OpenOCD Mailing List.

So how are flash driver functions developed?

Glad you asked! Have a look at Developing Flash Driver Functions