USBDM/CF (JMxx Version) V4.9.5

Programming with the USBDM API

Programming with the USBDM API is pretty straightforward. The documentation for the public API is documented in USBDM_API.h.

Below is a simple example of using the API to dump the entire flash from a MC9S08JM60 chip. You can click on the various functions and definitions used in the example to obtain more information.

Example

/*
 * Main.cpp
 *
 *  Created on: 21/4/2012
 *      Author: podonoghue
 *
 *  Simple program demonstrating use of USBDM API
 *
 *  This program dumps the contents of a chip to stdout in S19 format.
 */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
#include <memory.h> // linux
#else
#include <mem.h> // win
#endif
#include "USBDM_API.h"

// Required API
#define USBDM_API_VERSION_REQUIRED (40905) // Need V4.9.5

// Static check that correct API (header file) is being used
#if (USBDM_API_VERSION < USBDM_API_VERSION_REQUIRED)
#error "This program requires USBDM version 4.9.5 or later"
#endif

// Maximum size of a S-record, should be power of 2
const int maxSrecSize = (1<<4);

// Buffer for flash image
uint8_t buffer[0x20000];

// A region of flash to dump
//
typedef struct {
   uint32_t start;  //< start address (inclusive)
   uint32_t end;    //< end address (inclusive)
} MemRange;

// Describes target & region to dump
//
struct DeviceDescription {
   const char  *name;        //< Name of device
   TargetType_t targetType;  //< Target e.g. T_HCS12
   unsigned     numRanges;   //< Number of entries in ranges
   MemRange     ranges[10];  //< Ranges to dump
};
// Describes MC9S08JM60
DeviceDescription deviceDescriptionJM60 = {
      "MC9S08JM60",
      T_HCS08,
      2,
      {{0x10B0, 0x17FF},
       {0x1960, 0xFFFF},}
};
// Describes MC9S12NE64
DeviceDescription deviceDescriptionNE64 = {
      "MC9S12NE64",
      T_HCS12,
      2,
      {{0x4000, 0x7FFF},
       {0xC000, 0xFFFF},}
};
// Describes MCF51CN128
DeviceDescription deviceDescriptionCN128 = {
      "MCF51CN128",
      T_CFV1,
      1,
      {{0x000000, 0x01FFFF},}
};

// Check error code from USBDM API function
//
// @param rc - error code to access
//
// An error message is printed with line # and the program exited if
// rc indicates any error
//
void check(USBDM_ErrorCode rc, const char *file = NULL, unsigned lineNum = 0) {
   if (rc == BDM_RC_OK) {
      fprintf(stderr, "OK,     [%s:#%4d]\n", file, lineNum);
      return;
   }
   fprintf(stderr, "Failed, [%s:#%4d] Reason= %s\n", file, lineNum,  USBDM_GetErrorString(rc));
   USBDM_Close();
   USBDM_Exit();
   exit(rc);
}

// Convenience macro to add line number information to check()
//
#define CHECK(x) check((x), __FILE__, __LINE__)

// Dump a single S-record to stdout
//
// @param buffer   location of data to dump
// @param address  base address of data
// @param size     number of bytes to dump
//
// @note size must be less than or equal to \ref maxSrecSize
// @note S-records filled with 0xFF are discarded
//
void dumpSrec(uint8_t *buffer, uint32_t address, uint8_t size) {

   // Discard 0xFF filled records (blank Flash)
   bool allFF = true;
   for(int sub=0; sub<size; sub++) {
      if (buffer[sub] != 0xFF ) {
         allFF = false;
         break;
      }
   }
   if ((size == 0) || allFF) {
      return;
   }
   uint8_t *ptr = buffer;
   uint8_t checkSum;
   if ((address) < 0x10000U) {
      printf("S1%02X%04X", size+3, address);
      checkSum = size+3;
      checkSum += (address>>8)&0xFF;
      checkSum += (address)&0xFF;
   }
   else if (address < 0x1000000U) {
      printf("S2%02X%06X", size+4, address);
      checkSum = size+4;
      checkSum += (address>>16)&0xFF;
      checkSum += (address>>8)&0xFF;
      checkSum += (address)&0xFF;
   }
   else {
      printf("S3%02X%08X", size+5, address);
      checkSum = size+5;
      checkSum += (address>>24)&0xFF;
      checkSum += (address>>16)&0xFF;
      checkSum += (address>>8)&0xFF;
      checkSum += (address)&0xFF;
   }
   while (size-->0) {
      checkSum += *ptr;
      printf("%02X", *ptr++);
   }
   checkSum = checkSum^0xFF;
   printf("%02X\n", checkSum);
}

// Dump data as S-records to stdout
//
// @param buffer   location of data to dump
// @param address  base address of data
// @param size     number of bytes to dump
//
// @note Regions filled with 0xFF are discarded
//
void dump(uint8_t *buffer, uint32_t address, unsigned size) {
   while (size>0) {
      uint8_t oddBytes = address & (maxSrecSize-1);
      uint8_t srecSize = maxSrecSize - oddBytes;
      if (srecSize > size) {
         srecSize = (uint8_t) size;
      }
      dumpSrec(buffer, address, srecSize);
      address += srecSize;
      buffer  += srecSize;
      size    -= srecSize;
   }
}

// Dynamic check for USBDM DLL version
//
// @return BDM_RC_OK if successful
//
USBDM_ErrorCode checkAPI() {
   if (USBDM_DLLVersion() < USBDM_API_VERSION_REQUIRED) {
      return BDM_RC_WRONG_DLL_REVISION;
   }
   return BDM_RC_OK;
}

// Dump the contents of a chip
//
void dumpChip(DeviceDescription &deviceDescription) {
   fprintf(stderr, "Dumping %s\n", deviceDescription.name);

   CHECK(USBDM_Init());
   unsigned deviceCount;
   CHECK(USBDM_FindDevices(&deviceCount));
   CHECK(USBDM_Open(0));

   // Example of changing options, requires version >= V4.9.4
   USBDM_ExtendedOptions_t options = {
         sizeof(USBDM_ExtendedOptions_t),
         deviceDescription.targetType};
   CHECK(USBDM_GetDefaultExtendedOptions(&options));
   options.resetDuration         = 1000;
   options.resetReleaseInterval  = 500;
   options.resetRecoveryInterval = 1500;
   options.targetVdd             = BDM_TARGET_VDD_3V3;
   options.autoReconnect         = AUTOCONNECT_STATUS;
   CHECK(USBDM_SetExtendedOptions(&options));

   CHECK(USBDM_SetTargetType(deviceDescription.targetType));
   CHECK(USBDM_TargetReset((TargetMode_t)(RESET_SPECIAL|RESET_DEFAULT))); // >= V4.9.4
   CHECK(USBDM_Connect());
   memset(buffer, 0xFF, sizeof(buffer));
   for (unsigned sub=0;
        sub<deviceDescription.numRanges;
        sub++) {
      fprintf(stderr, "Range [0x%06X-0x%06X]\n",
            deviceDescription.ranges[sub].start, deviceDescription.ranges[sub].end);
      CHECK(USBDM_ReadMemory(1,
            deviceDescription.ranges[sub].end-deviceDescription.ranges[sub].start+1,
            deviceDescription.ranges[sub].start,
            buffer+(deviceDescription.ranges[sub].start&0xFFFF)));
   }
   USBDM_Close();
   USBDM_Exit();
   dump(buffer, 0x0000, sizeof(buffer));
}

int main(int argc, char *argv[]) {

   CHECK(checkAPI());

   int option = 0;
   if (argc > 1) {
      option = atoi(argv[1]);
   }
   switch(option) {
   default:
   case 0: dumpChip(deviceDescriptionNE64);  break;
   case 1: dumpChip(deviceDescriptionJM60);  break;
   case 2: dumpChip(deviceDescriptionCN128); break;
   }
   return 0;
}