lib: Add bossac 1.9 code to lib directory

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-08-16 17:03:23 -04:00
parent 79632878ac
commit 2b9124f3c0
36 changed files with 6287 additions and 0 deletions

64
lib/bossac/src/Applet.cpp Normal file
View file

@ -0,0 +1,64 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "Applet.h"
Applet::Applet(Samba& samba,
uint32_t addr,
uint8_t* code,
uint32_t size,
uint32_t start,
uint32_t stack,
uint32_t reset) :
_samba(samba), _addr(addr), _size(size), _start(start), _stack(stack), _reset(reset)
{
_samba.write(addr, code, size);
}
void
Applet::setStack(uint32_t stack)
{
_samba.writeWord(_stack, stack);
}
void
Applet::run()
{
// Add one to the start address for Thumb mode
_samba.go(_start + 1);
}
void
Applet::runv()
{
// Add one to the start address for Thumb mode
_samba.writeWord(_reset, _start + 1);
// The stack is the first reset vector
_samba.go(_stack);
}

65
lib/bossac/src/Applet.h Normal file
View file

@ -0,0 +1,65 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _APPLET_H
#define _APPLET_H
#include <stdint.h>
#include "Samba.h"
class Applet
{
public:
Applet(Samba& samba,
uint32_t addr,
uint8_t* code,
uint32_t size,
uint32_t start,
uint32_t stack,
uint32_t reset);
virtual ~Applet() {}
virtual uint32_t size() { return _size; }
virtual uint32_t addr() { return _addr; }
virtual void setStack(uint32_t stack);
virtual void run(); // To be used for Thumb-1 based devices (ARM7TDMI, ARM9)
virtual void runv(); // To be used for Thumb-2 based devices (Cortex-Mx)
protected:
Samba& _samba;
uint32_t _addr; // Address in device SRAM where will be placed the applet
uint32_t _size; // Applet size
uint32_t _start; //
uint32_t _stack; // Applet stack address in device SRAM
uint32_t _reset;
};
#endif // _APPLET_H

159
lib/bossac/src/CmdOpts.cpp Normal file
View file

@ -0,0 +1,159 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <assert.h>
#include "CmdOpts.h"
CmdOpts::CmdOpts(int argc, char* argv[], int numOpts, Option* opts) :
_argc(argc), _argv(argv), _numOpts(numOpts), _opts(opts)
{
}
CmdOpts::~CmdOpts()
{
}
void
CmdOpts::usage(FILE* out)
{
int optIdx;
char name[40];
const char* start;
const char* end;
for (optIdx = 0; optIdx < _numOpts; optIdx++)
{
if (_opts[optIdx].arg.has == ArgOptional)
snprintf(name, sizeof(name), " -%c, --%s[=%s]",
_opts[optIdx].letter,
_opts[optIdx].name,
_opts[optIdx].arg.name);
else if (_opts[optIdx].arg.has == ArgRequired)
snprintf(name, sizeof(name), " -%c, --%s=%s",
_opts[optIdx].letter,
_opts[optIdx].name,
_opts[optIdx].arg.name);
else
snprintf(name, sizeof(name), " -%c, --%s",
_opts[optIdx].letter,
_opts[optIdx].name);
fprintf(out, "%-23s ", name);
start = _opts[optIdx].help;
while ((end = strchr(start, '\n')))
{
fwrite(start, end - start + 1, 1, out);
fprintf(out, "%24s", "");
start = end + 1;
}
fprintf(out, "%s\n", start);
}
}
int
CmdOpts::parse()
{
struct option long_opts[_numOpts + 1];
char optstring[_numOpts * 3 + 1];
char* optPtr = optstring;
int optIdx;
int rc;
for (optIdx = 0; optIdx < _numOpts; optIdx++)
{
*_opts[optIdx].present = false;
*optPtr++ = _opts[optIdx].letter;
long_opts[optIdx].name = _opts[optIdx].name;
switch (_opts[optIdx].arg.has)
{
default:
case ArgNone:
long_opts[optIdx].has_arg = no_argument;
break;
case ArgOptional:
long_opts[optIdx].has_arg = optional_argument;
*optPtr++ = ':';
*optPtr++ = ':';
break;
case ArgRequired:
long_opts[optIdx].has_arg = required_argument;
*optPtr++ = ':';
break;
}
long_opts[optIdx].flag = NULL;
long_opts[optIdx].val = 0;
}
memset(&long_opts[_numOpts], 0, sizeof(long_opts[_numOpts]));
*optPtr = '\0';
optIdx = 0;
while ((rc = getopt_long(_argc, _argv, optstring, long_opts, &optIdx)) != -1)
{
if (rc == '?')
return -1;
if (rc != 0)
optIdx = find(rc);
assert(optIdx >= 0 && optIdx < _numOpts);
*_opts[optIdx].present = true;
if (_opts[optIdx].arg.has != ArgNone && optarg)
{
switch (_opts[optIdx].arg.type)
{
case ArgInt:
*_opts[optIdx].arg.value.intPtr = strtol(optarg, NULL, 0);
break;
default:
case ArgString:
*_opts[optIdx].arg.value.strPtr = optarg;
break;
}
}
}
return optind;
}
int
CmdOpts::find(char letter)
{
int optIdx;
for (optIdx = 0; optIdx < _numOpts; optIdx++)
if (_opts[optIdx].letter == letter)
break;
return optIdx;
}

88
lib/bossac/src/CmdOpts.h Normal file
View file

@ -0,0 +1,88 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _OPTION_H
#define _OPTION_H
#include <string>
#include <stdio.h>
typedef enum
{
ArgNone,
ArgOptional,
ArgRequired
} ArgHas;
typedef enum
{
ArgInt,
ArgString
} ArgType;
typedef struct
{
ArgHas has;
ArgType type;
const char* name;
union
{
void* voidPtr;
int* intPtr;
std::string* strPtr;
} value;
} OptArg;
typedef struct
{
char letter;
const char* name;
bool* present;
OptArg arg;
const char* help;
} Option;
class CmdOpts
{
public:
CmdOpts(int argc, char* argv[], int numOpts, Option* opts);
virtual ~CmdOpts();
void usage(FILE* out);
int parse();
private:
int _argc;
char** _argv;
int _numOpts;
Option* _opts;
int find(char letter);
};
#endif // _OPTION_H

View file

@ -0,0 +1,347 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2018, ShumaTech
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
///////////////////////////////////////////////////////////////////////////////
#include "D2xNvmFlash.h"
// CMDEX field should be 0xA5 to allow execution of any command.
#define CMDEX_KEY 0xa500
// NVM ready bit mask
#define NVM_INT_STATUS_READY_MASK 0x1
// NVM status mask
#define NVM_CTRL_STATUS_MASK 0xFFEB
#define NVM_REG_BASE 0x41004000
#define NVM_REG_CTRLA 0x00
#define NVM_REG_CTRLB 0x04
#define NVM_REG_INTFLAG 0x14
#define NVM_REG_STATUS 0x18
#define NVM_REG_ADDR 0x1c
#define NVM_REG_LOCK 0x20
#define NVM_CMD_ER 0x02
#define NVM_CMD_WP 0x04
#define NVM_CMD_EAR 0x05
#define NVM_CMD_WAP 0x06
#define NVM_CMD_LR 0x40
#define NVM_CMD_UR 0x41
#define NVM_CMD_SSB 0x45
#define NVM_CMD_PBC 0x44
#define ERASE_ROW_PAGES 4 // pages
// NVM User Row
#define NVM_UR_ADDR 0x804000
#define NVM_UR_SIZE (_size * ERASE_ROW_PAGES)
#define NVM_UR_BOD33_ENABLE_OFFSET 0x1
#define NVM_UR_BOD33_ENABLE_MASK 0x6
#define NVM_UR_BOD33_RESET_OFFSET 0x1
#define NVM_UR_BOD33_RESET_MASK 0x7
#define NVM_UR_NVM_LOCK_OFFSET 0x6
D2xNvmFlash::D2xNvmFlash(
Samba& samba,
const std::string& name,
uint32_t pages,
uint32_t size,
uint32_t user,
uint32_t stack)
:
Flash(samba, name, 0, pages, size, 1, 16, user, stack), _eraseAuto(true)
{
}
D2xNvmFlash::~D2xNvmFlash()
{
}
void
D2xNvmFlash::erase(uint32_t offset, uint32_t size)
{
uint32_t eraseSize = _size * ERASE_ROW_PAGES;
// Offset must be a multiple of the erase size
if (offset % eraseSize)
throw FlashEraseError();
// Offset and size must be in range
if (offset + size > totalSize())
throw FlashEraseError();
uint32_t eraseEnd = (offset + size + eraseSize - 1) / eraseSize;
// Erase each erase size set of pages
for (uint32_t eraseNum = offset / eraseSize; eraseNum < eraseEnd; eraseNum++)
{
waitReady();
// Clear error bits
uint16_t statusReg = readReg(NVM_REG_STATUS);
writeReg(NVM_REG_STATUS, statusReg | NVM_CTRL_STATUS_MASK);
// Issue erase command
uint32_t wordAddr = (eraseNum * eraseSize) / 2;
writeReg(NVM_REG_ADDR, wordAddr);
command(NVM_CMD_ER);
}
}
void
D2xNvmFlash::eraseAll(uint32_t offset)
{
// Use the extended Samba command if available
if (_samba.canChipErase())
{
_samba.chipErase(offset);
}
else
{
erase(offset, totalSize() - offset);
}
}
void
D2xNvmFlash::eraseAuto(bool enable)
{
_eraseAuto = enable;
}
std::vector<bool>
D2xNvmFlash::getLockRegions()
{
uint8_t lockBits = 0;
uint32_t addr = NVM_UR_ADDR + NVM_UR_NVM_LOCK_OFFSET;
std::vector<bool> regions(_lockRegions);
for (uint32_t region = 0; region < _lockRegions; region++)
{
if (region % 8 == 0)
lockBits = _samba.readByte(addr++);
regions[region] = (lockBits & (1 << (region % 8))) == 0;
}
return regions;
}
bool
D2xNvmFlash::getSecurity()
{
return (readReg(NVM_REG_STATUS) & 0x100) != 0;
}
bool
D2xNvmFlash::getBod()
{
uint8_t byte = _samba.readByte(NVM_UR_ADDR + NVM_UR_BOD33_ENABLE_OFFSET);
return (byte & NVM_UR_BOD33_ENABLE_MASK) != 0;
}
bool
D2xNvmFlash::getBor()
{
uint8_t byte = _samba.readByte(NVM_UR_ADDR + NVM_UR_BOD33_RESET_OFFSET);
return (byte & NVM_UR_BOD33_RESET_MASK) != 0;
}
bool
D2xNvmFlash::getBootFlash()
{
return true;
}
void
D2xNvmFlash::readUserRow(std::unique_ptr<uint8_t[]>& userRow)
{
if (!userRow)
{
userRow.reset(new uint8_t[NVM_UR_SIZE]);
_samba.read(NVM_UR_ADDR, userRow.get(), NVM_UR_SIZE);
}
}
void
D2xNvmFlash::writeOptions()
{
std::unique_ptr<uint8_t[]> userRow;
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
{
readUserRow(userRow);
if (_bor.get())
userRow[NVM_UR_BOD33_RESET_OFFSET] |= NVM_UR_BOD33_RESET_MASK;
else
userRow[NVM_UR_BOD33_RESET_OFFSET] &= ~NVM_UR_BOD33_RESET_MASK;
}
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
{
readUserRow(userRow);
if (_bod.get())
userRow[NVM_UR_BOD33_ENABLE_OFFSET] |= NVM_UR_BOD33_ENABLE_MASK;
else
userRow[NVM_UR_BOD33_ENABLE_OFFSET] &= ~NVM_UR_BOD33_ENABLE_MASK;
}
if (_regions.isDirty())
{
// Check if any lock bits are different from the current set
std::vector<bool> current = getLockRegions();
if (!equal(_regions.get().begin(), _regions.get().end(), current.begin()))
{
readUserRow(userRow);
uint8_t* lockBits = &userRow[NVM_UR_NVM_LOCK_OFFSET];
for (uint32_t region = 0; region < _regions.get().size(); region++)
{
if (_regions.get()[region])
lockBits[region / 8] &= ~(1 << (region % 8));
else
lockBits[region / 8] |= (1 << (region % 8));
}
}
}
// Erase and write the user row if modified
if (userRow)
{
// Disable cache and configure manual page write
writeReg(NVM_REG_CTRLB, readReg(NVM_REG_CTRLB) | (0x1 << 18) | (0x1 << 7));
// Erase user row
writeReg(NVM_REG_ADDR, NVM_UR_ADDR / 2);
command(NVM_CMD_EAR);
// Write user row in page chunks
for (uint32_t offset = 0; offset < NVM_UR_SIZE; offset += _size)
{
// Load the buffer with the page
loadBuffer(&userRow[offset], _size);
// Clear page buffer
command(NVM_CMD_PBC);
// Copy page to page buffer
_wordCopy.setDstAddr(NVM_UR_ADDR + offset);
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_onBufferA = !_onBufferA;
waitReady();
_wordCopy.runv();
// Write the page
writeReg(NVM_REG_ADDR, (NVM_UR_ADDR + offset) / 2);
command(NVM_CMD_WAP);
}
}
// Always do security last
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
{
command(NVM_CMD_SSB);
}
}
void
D2xNvmFlash::writePage(uint32_t page)
{
if (page >= _pages)
{
throw FlashPageError();
}
// Disable cache and configure manual page write
writeReg(NVM_REG_CTRLB, readReg(NVM_REG_CTRLB) | (0x1 << 18) | (0x1 << 7));
// Auto-erase if writing at the start of the erase page
if (_eraseAuto && page % ERASE_ROW_PAGES == 0)
erase(page * _size, ERASE_ROW_PAGES * _size);
// Clear page buffer
command(NVM_CMD_PBC);
// Compute the start address.
uint32_t addr = _addr + (page * _size);
_wordCopy.setDstAddr(addr);
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_onBufferA = !_onBufferA;
waitReady();
_wordCopy.runv();
writeReg(NVM_REG_ADDR, addr / 2);
command(NVM_CMD_WP);
}
void
D2xNvmFlash::waitReady()
{
while ((readReg(NVM_REG_INTFLAG) & 0x1) == 0);
}
void
D2xNvmFlash::readPage(uint32_t page, uint8_t* buf)
{
if (page >= _pages)
{
throw FlashPageError();
}
_samba.read(_addr + (page * _size), buf, _size);
}
uint32_t
D2xNvmFlash::readReg(uint8_t reg)
{
return _samba.readWord(NVM_REG_BASE + reg);
}
void
D2xNvmFlash::writeReg(uint8_t reg, uint32_t value)
{
_samba.writeWord(NVM_REG_BASE + reg, value);
}
void
D2xNvmFlash::command(uint8_t cmd)
{
waitReady();
writeReg(NVM_REG_CTRLA, CMDEX_KEY | cmd);
waitReady();
if (readReg(NVM_REG_INTFLAG) & 0x2)
{
// Clear the error bit
writeReg(NVM_REG_INTFLAG, 0x2);
throw FlashCmdError();
}
}
void
D2xNvmFlash::writeBuffer(uint32_t dst_addr, uint32_t size)
{
// Auto-erase if enabled
if (_eraseAuto)
erase(dst_addr, size);
// Call the base class method
Flash::writeBuffer(dst_addr, size);
}

View file

@ -0,0 +1,76 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2018, ShumaTech
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
///////////////////////////////////////////////////////////////////////////////
#ifndef _D2XNVMFLASH_H
#define _D2XNVMFLASH_H
#include <stdint.h>
#include <exception>
#include "Flash.h"
class D2xNvmFlash : public Flash
{
public:
D2xNvmFlash(
Samba& samba,
const std::string& name,
uint32_t pages,
uint32_t size,
uint32_t user,
uint32_t stack);
virtual ~D2xNvmFlash();
void eraseAll(uint32_t offset);
void eraseAuto(bool enable);
std::vector<bool> getLockRegions();
bool getSecurity();
bool getBod();
bool canBod() { return true; }
bool getBor();
bool canBor() { return true; }
bool getBootFlash();
bool canBootFlash() { return false; }
void writeOptions();
void writePage(uint32_t page);
void readPage(uint32_t page, uint8_t* data);
void writeBuffer(uint32_t dst_addr, uint32_t size);
protected:
bool _eraseAuto;
uint32_t readReg(uint8_t reg);
void writeReg(uint8_t reg, uint32_t value);
void waitReady();
void command(uint8_t cmd);
void erase(uint32_t offset, uint32_t size);
void readUserRow(std::unique_ptr<uint8_t[]>& userRow);
};
#endif // _D2XNVMFLASH_H

View file

@ -0,0 +1,352 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2018, ShumaTech
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
///////////////////////////////////////////////////////////////////////////////
#include "D5xNvmFlash.h"
#define CMDEX_KEY 0xa500
#define NVM_REG_BASE 0x41004000
#define NVM_REG_CTRLA 0x00
#define NVM_REG_CTRLB 0x04
#define NVM_REG_INTFLAG 0x10
#define NVM_REG_STATUS 0x12
#define NVM_REG_ADDR 0x14
#define NVM_REG_RUNLOCK 0x18
#define NVM_CMD_EP 0x00
#define NVM_CMD_EB 0x01
#define NVM_CMD_WP 0x03
#define NVM_CMD_WQW 0x04
#define NVM_CMD_LR 0x11
#define NVM_CMD_UR 0x12
#define NVM_CMD_SSB 0x16
#define NVM_CMD_PBC 0x15
#define ERASE_BLOCK_PAGES 16 // pages
// NVM User Page
#define NVM_UP_ADDR 0x804000
#define NVM_UP_SIZE (_size)
#define NVM_UP_BOD33_DISABLE_OFFSET 0x0
#define NVM_UP_BOD33_DISABLE_MASK 0x1
#define NVM_UP_BOD33_RESET_OFFSET 0x1
#define NVM_UP_BOD33_RESET_MASK 0x2
#define NVM_UP_NVM_LOCK_OFFSET 0x8
D5xNvmFlash::D5xNvmFlash(
Samba& samba,
const std::string& name,
uint32_t pages,
uint32_t size,
uint32_t user,
uint32_t stack)
:
Flash(samba, name, 0, pages, size, 1, 32, user, stack), _eraseAuto(true)
{
}
D5xNvmFlash::~D5xNvmFlash()
{
}
void
D5xNvmFlash::erase(uint32_t offset, uint32_t size)
{
uint32_t eraseSize = _size * ERASE_BLOCK_PAGES;
// Offset must be a multiple of the erase size
if (offset % eraseSize)
throw FlashEraseError();
// Offset and size must be in range
if (offset + size > totalSize())
throw FlashEraseError();
uint32_t eraseEnd = (offset + size + eraseSize - 1) / eraseSize;
// Erase each erase size set of pages
for (uint32_t eraseNum = offset / eraseSize; eraseNum < eraseEnd; eraseNum++)
{
// Issue erase command
writeRegU32(NVM_REG_ADDR, eraseNum * eraseSize);
command(NVM_CMD_EB);
}
}
void
D5xNvmFlash::eraseAll(uint32_t offset)
{
// Use the extended Samba command if available
if (_samba.canChipErase())
{
_samba.chipErase(offset);
}
else
{
erase(offset, totalSize() - offset);
}
}
void
D5xNvmFlash::waitReady()
{
while ((readRegU16(NVM_REG_STATUS) & 0x1) == 0);
}
void
D5xNvmFlash::eraseAuto(bool enable)
{
_eraseAuto = enable;
}
std::vector<bool>
D5xNvmFlash::getLockRegions()
{
uint8_t lockBits = 0;
uint32_t addr = NVM_UP_ADDR + NVM_UP_NVM_LOCK_OFFSET;
std::vector<bool> regions(_lockRegions);
for (uint32_t region = 0; region < _lockRegions; region++)
{
if (region % 8 == 0)
lockBits = _samba.readByte(addr++);
regions[region] = (lockBits & (1 << (region % 8))) == 0;
}
return regions;
}
bool
D5xNvmFlash::getSecurity()
{
// There doesn't seem to be a way to read this
return false;
}
bool
D5xNvmFlash::getBod()
{
uint8_t byte = _samba.readByte(NVM_UP_ADDR + NVM_UP_BOD33_DISABLE_OFFSET);
return (byte & NVM_UP_BOD33_DISABLE_MASK) == 0;
}
bool
D5xNvmFlash::getBor()
{
uint8_t byte = _samba.readByte(NVM_UP_ADDR + NVM_UP_BOD33_RESET_OFFSET);
return (byte & NVM_UP_BOD33_RESET_MASK) != 0;
}
bool
D5xNvmFlash::getBootFlash()
{
return true;
}
void
D5xNvmFlash::readUserPage(std::unique_ptr<uint8_t[]>& userPage)
{
if (!userPage)
{
userPage.reset(new uint8_t[NVM_UP_SIZE]);
_samba.read(NVM_UP_ADDR, userPage.get(), NVM_UP_SIZE);
}
}
void
D5xNvmFlash::writeOptions()
{
std::unique_ptr<uint8_t[]> userPage;
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
{
readUserPage(userPage);
if (_bor.get())
userPage[NVM_UP_BOD33_RESET_OFFSET] |= NVM_UP_BOD33_RESET_MASK;
else
userPage[NVM_UP_BOD33_RESET_OFFSET] &= ~NVM_UP_BOD33_RESET_MASK;
}
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
{
readUserPage(userPage);
if (_bod.get())
userPage[NVM_UP_BOD33_DISABLE_OFFSET] &= ~NVM_UP_BOD33_DISABLE_MASK;
else
userPage[NVM_UP_BOD33_DISABLE_OFFSET] |= NVM_UP_BOD33_DISABLE_MASK;
}
if (_regions.isDirty())
{
// Check if any lock bits are different from the current set
std::vector<bool> current = getLockRegions();
if (!equal(_regions.get().begin(), _regions.get().end(), current.begin()))
{
readUserPage(userPage);
uint8_t* lockBits = &userPage[NVM_UP_NVM_LOCK_OFFSET];
for (uint32_t region = 0; region < _regions.get().size(); region++)
{
if (_regions.get()[region])
lockBits[region / 8] &= ~(1 << (region % 8));
else
lockBits[region / 8] |= (1 << (region % 8));
}
}
}
// Erase and write the user page if modified
if (userPage)
{
// Configure manual page write and disable caches
writeRegU16(NVM_REG_CTRLA, (readRegU16(NVM_REG_CTRLA) | (0x3 << 14)) & 0xffcf);
// Erase user page
writeRegU32(NVM_REG_ADDR, NVM_UP_ADDR);
command(NVM_CMD_EP);
// Write user page in quad-word chunks
for (uint32_t offset = 0; offset < NVM_UP_SIZE; offset += 16)
{
// Load the buffer with the quad word
loadBuffer(&userPage[offset], 16);
// Clear page buffer
command(NVM_CMD_PBC);
// Copy quad word to page buffer
_wordCopy.setDstAddr(NVM_UP_ADDR + offset);
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_wordCopy.setWords(4);
_onBufferA = !_onBufferA;
waitReady();
_wordCopy.runv();
// Write the quad word
writeRegU32(NVM_REG_ADDR, NVM_UP_ADDR + offset);
command(NVM_CMD_WQW);
}
}
// Always do security last
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
{
command(NVM_CMD_SSB);
}
}
void
D5xNvmFlash::writePage(uint32_t page)
{
if (page >= _pages)
{
throw FlashPageError();
}
// Configure manual page write and disable caches
writeRegU16(NVM_REG_CTRLA, (readRegU16(NVM_REG_CTRLA) | (0x3 << 14)) & 0xffcf);
// Auto-erase if writing at the start of the erase page
if (_eraseAuto && page % ERASE_BLOCK_PAGES == 0)
{
erase(page * _size, ERASE_BLOCK_PAGES * _size);
}
// Clear page bur
command(NVM_CMD_PBC);
uint32_t addr = _addr + (page * _size );
_wordCopy.setDstAddr(addr);
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_wordCopy.setWords(_size / sizeof(uint32_t));
_onBufferA = !_onBufferA;
waitReady();
_wordCopy.runv();
writeRegU32(NVM_REG_ADDR, addr);
command(NVM_CMD_WP);
}
void
D5xNvmFlash::readPage(uint32_t page, uint8_t* buf)
{
if (page >= _pages)
{
throw FlashPageError();
}
_samba.read(_addr + (page * _size), buf, _size);
}
uint16_t
D5xNvmFlash::readRegU16(uint8_t reg)
{
return (uint16_t) _samba.readByte(NVM_REG_BASE + reg) |
(_samba.readByte(NVM_REG_BASE + reg + 1) << 8);
}
void
D5xNvmFlash::writeRegU16(uint8_t reg, uint16_t value)
{
_samba.writeByte(NVM_REG_BASE + reg, value & 0xff);
_samba.writeByte(NVM_REG_BASE + reg + 1, value >> 8);
}
uint32_t
D5xNvmFlash::readRegU32(uint8_t reg)
{
return _samba.readWord(NVM_REG_BASE + reg);
}
void
D5xNvmFlash::writeRegU32(uint8_t reg, uint32_t value)
{
_samba.writeWord(NVM_REG_BASE + reg, value);
}
void
D5xNvmFlash::command(uint8_t cmd)
{
waitReady();
writeRegU32(NVM_REG_CTRLB, CMDEX_KEY | cmd);
waitReady();
if (readRegU16(NVM_REG_INTFLAG) & 0xce)
{
// Clear the error bits
writeRegU16(NVM_REG_INTFLAG, 0xce);
throw FlashCmdError();
}
}
void
D5xNvmFlash::writeBuffer(uint32_t dst_addr, uint32_t size)
{
// Auto-erase if writing at the start of the erase page
if (_eraseAuto && ((dst_addr / _size) % ERASE_BLOCK_PAGES == 0))
erase(dst_addr, size);
// Call the base class method
Flash::writeBuffer(dst_addr, size);
}

View file

@ -0,0 +1,79 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2018, ShumaTech
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
///////////////////////////////////////////////////////////////////////////////
#ifndef _D5XNVMFLASH_H
#define _D5XNVMFLASH_H
#include <stdint.h>
#include <exception>
#include "Flash.h"
class D5xNvmFlash : public Flash
{
public:
D5xNvmFlash(
Samba& samba,
const std::string& name,
uint32_t pages,
uint32_t size,
uint32_t user,
uint32_t stack);
virtual ~D5xNvmFlash();
void eraseAll(uint32_t offset);
void eraseAuto(bool enable);
std::vector<bool> getLockRegions();
bool getSecurity();
bool getBod();
bool canBod() { return true; }
bool getBor();
bool canBor() { return true; }
bool getBootFlash();
bool canBootFlash() { return false; }
void writeOptions();
void writePage(uint32_t page);
void readPage(uint32_t page, uint8_t* data);
void writeBuffer(uint32_t dst_addr, uint32_t size);
protected:
bool _eraseAuto;
uint16_t readRegU16(uint8_t reg);
void writeRegU16(uint8_t reg, uint16_t value);
uint32_t readRegU32(uint8_t reg);
void writeRegU32(uint8_t reg, uint32_t value);
void waitReady();
void command(uint8_t cmd);
void erase(uint32_t offset, uint32_t size);
void checkError();
void readUserPage(std::unique_ptr<uint8_t[]>& userPage);
};
#endif // _D5XNVMFLASH_H

692
lib/bossac/src/Device.cpp Normal file
View file

@ -0,0 +1,692 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "Device.h"
#include "EfcFlash.h"
#include "EefcFlash.h"
#include "D2xNvmFlash.h"
#include "D5xNvmFlash.h"
void
Device::readChipId(uint32_t& chipId, uint32_t& extChipId)
{
if ((chipId = _samba.readWord(0x400e0740)) != 0)
{
extChipId = _samba.readWord(0x400e0744);
}
else if ((chipId = _samba.readWord(0x400e0940)) != 0)
{
extChipId = _samba.readWord(0x400e0944);
}
}
void
Device::create()
{
Flash* flashPtr;
uint32_t chipId = 0;
uint32_t cpuId = 0;
uint32_t extChipId = 0;
uint32_t deviceId = 0;
// Device identification must be performed carefully to avoid reading from
// addresses that devices do not support which will lock up the CPU
// All devices support addresss 0 as the ARM reset vector so if the vector is
// a ARM7TDMI branch, then assume we have an Atmel SAM7/9 CHIPID register
if ((_samba.readWord(0x0) & 0xff000000) == 0xea000000)
{
chipId = _samba.readWord(0xfffff240);
}
else
{
// Next try the ARM CPUID register since all Cortex-M devices support it
cpuId = _samba.readWord(0xe000ed00) & 0x0000fff0;
// Cortex-M0+
if (cpuId == 0xC600)
{
// These should support the ARM device ID register
deviceId = _samba.readWord(0x41002018);
}
// Cortex-M4
else if (cpuId == 0xC240)
{
// SAM4 processors have a reset vector to the SAM-BA ROM
if ((_samba.readWord(0x4) & 0xfff00000) == 0x800000)
{
readChipId(chipId, extChipId);
}
// Else we should have a device that supports the ARM device ID register
else
{
deviceId = _samba.readWord(0x41002018);
}
}
// For all other Cortex versions try the Atmel chip ID registers
else
{
readChipId(chipId, extChipId);
}
}
// Instantiate the proper flash for the device
switch (chipId & 0x7fffffe0)
{
//
// SAM7SE
//
case 0x272a0a40:
_family = FAMILY_SAM7SE;
flashPtr = new EfcFlash(_samba, "AT91SAM7SE512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x208000, true);
break;
case 0x272a0940:
_family = FAMILY_SAM7SE;
flashPtr = new EfcFlash(_samba, "AT91SAM7SE256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x208000, true);
break;
case 0x272a0340:
_family = FAMILY_SAM7SE;
flashPtr = new EfcFlash(_samba, "AT91SAM7SE32", 0x100000, 256, 128, 1, 8, 0x201400, 0x201C00, true);
break;
//
// SAM7S
//
case 0x270b0a40:
_family = FAMILY_SAM7S;
flashPtr = new EfcFlash(_samba, "AT91SAM7S512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x210000, false);
break;
case 0x270d0940: // A
case 0x270b0940: // B/C
_family = FAMILY_SAM7S;
flashPtr = new EfcFlash(_samba, "AT91SAM7S256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, false);
break;
case 0x270c0740: // A
case 0x270a0740: // B/C
_family = FAMILY_SAM7S;
flashPtr = new EfcFlash(_samba, "AT91SAM7S128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, false);
break;
case 0x27090540:
_family = FAMILY_SAM7S;
flashPtr = new EfcFlash(_samba, "AT91SAM7S64", 0x100000, 512, 128, 1, 16, 0x202000, 0x204000, false);
break;
case 0x27080340:
_family = FAMILY_SAM7S;
flashPtr = new EfcFlash(_samba, "AT91SAM7S32", 0x100000, 256, 128, 1, 8, 0x201400, 0x202000, false);
break;
case 0x27050240:
_family = FAMILY_SAM7S;
flashPtr = new EfcFlash(_samba, "AT91SAM7S16", 0x100000, 256, 64, 1, 8, 0x200000, 0x200e00, false);
break;
//
// SAM7XC
//
case 0x271c0a40:
_family = FAMILY_SAM7XC;
flashPtr = new EfcFlash(_samba, "AT91SAMXC512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x220000, true);
break;
case 0x271b0940:
_family = FAMILY_SAM7XC;
flashPtr = new EfcFlash(_samba, "AT91SAMXC256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, true);
break;
case 0x271a0740:
_family = FAMILY_SAM7XC;
flashPtr = new EfcFlash(_samba, "AT91SAMXC128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, true);
break;
//
// SAM7X
//
case 0x275c0a40:
_family = FAMILY_SAM7X;
flashPtr = new EfcFlash(_samba, "AT91SAMX512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x220000, true);
break;
case 0x275b0940:
_family = FAMILY_SAM7X;
flashPtr = new EfcFlash(_samba, "AT91SAMX256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, true);
break;
case 0x275a0740:
_family = FAMILY_SAM7X;
flashPtr = new EfcFlash(_samba, "AT91SAMX128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, true);
break;
//
// SAM4S
//
case 0x29870ee0: // A
case 0x29970ee0: // B
case 0x29A70ee0: // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4SD32", 0x400000, 4096, 512, 2, 256, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x29870c30: // A
case 0x29970c30: // B
case 0x29a70c30: // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4SD16", 0x400000, 2048, 512, 2, 256, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x28870ce0: // A
case 0x28970ce0: // B
case 0x28A70ce0: // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4SA16", 0x400000, 2048, 512, 1, 256, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x288c0ce0 : // A
case 0x289c0ce0 : // B
case 0x28ac0ce0 : // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4S16", 0x400000, 2048, 512, 1, 128, 0x20001000, 0x20020000, 0x400e0a00, false);
break;
case 0x288c0ae0 : // A
case 0x289c0ae0 : // B
case 0x28ac0ae0 : // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4S8", 0x400000, 1024, 512, 1, 64, 0x20001000, 0x20020000, 0x400e0a00, false);
break;
case 0x288b09e0 : // A
case 0x289b09e0 : // B
case 0x28ab09e0 : // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4S4", 0x400000, 512, 512, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x288b07e0 : // A
case 0x289b07e0 : // B
case 0x28ab07e0 : // C
_family = FAMILY_SAM4S;
flashPtr = new EefcFlash(_samba, "ATSAM4S2", 0x400000, 256, 512, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
//
// SAM3N
//
case 0x29340960 : // A
case 0x29440960 : // B
case 0x29540960 : // C
_family = FAMILY_SAM3N;
flashPtr = new EefcFlash(_samba, "ATSAM3N4", 0x400000, 1024, 256, 1, 16, 0x20001000, 0x20006000, 0x400e0a00, false);
break;
case 0x29390760 : // A
case 0x29490760 : // B
case 0x29590760 : // C
_family = FAMILY_SAM3N;
flashPtr = new EefcFlash(_samba, "ATSAM3N2", 0x400000, 512, 256, 1, 8, 0x20001000, 0x20004000, 0x400e0a00, false);
break;
case 0x29380560 : // A
case 0x29480560 : // B
case 0x29580560 : // C
_family = FAMILY_SAM3N;
flashPtr = new EefcFlash(_samba, "ATSAM3N1", 0x400000, 256, 256, 1, 4, 0x20000800, 0x20002000, 0x400e0a00, false);
break;
case 0x29380360 : // A
case 0x29480360 : // B
case 0x29580360 : // C
_family = FAMILY_SAM3N;
flashPtr = new EefcFlash(_samba, "ATSAM3N0", 0x400000, 128, 256, 1, 1, 0x20000800, 0x20002000, 0x400e0a00, false);
break;
//
// SAM3S
//
case 0x299b0a60 : // B
case 0x29ab0a60 : // C
_family = FAMILY_SAM3S;
flashPtr = new EefcFlash(_samba, "ATSAM3SD8", 0x400000, 2048, 256, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x289b0a60 : // B
case 0x28ab0a60 : // C
_family = FAMILY_SAM3S;
flashPtr = new EefcFlash(_samba, "ATSAM3S8", 0x400000, 2048, 256, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x28800960 : // A
case 0x28900960 : // B
case 0x28a00960 : // C
_family = FAMILY_SAM3S;
flashPtr = new EefcFlash(_samba, "ATSAM3S4", 0x400000, 1024, 256, 1, 16, 0x20001000, 0x2000c000, 0x400e0a00, false);
break;
case 0x288a0760 : // A
case 0x289a0760 : // B
case 0x28aa0760 : // C
_family = FAMILY_SAM3S;
flashPtr = new EefcFlash(_samba, "ATSAM3S2", 0x400000, 512, 256, 1, 8, 0x20000800, 0x20008000, 0x400e0a00, false);
break;
case 0x288a0560 : // A
case 0x289a0560 : // B
case 0x28aa0560 : // C
_family = FAMILY_SAM3S;
flashPtr = new EefcFlash(_samba, "ATSAM3S1", 0x400000, 256, 256, 1, 4, 0x20000800, 0x20004000, 0x400e0a00, false);
break;
//
// SAM3U
//
case 0x28000960 : // C
case 0x28100960 : // E
_family = FAMILY_SAM3U;
flashPtr = new EefcFlash(_samba, "ATSAM3U4", 0xE0000, 1024, 256, 2, 32, 0x20001000, 0x20008000, 0x400e0800, false);
break;
case 0x280a0760 : // C
case 0x281a0760 : // E
_family = FAMILY_SAM3U;
flashPtr = new EefcFlash(_samba, "ATSAM3U2", 0x80000, 512, 256, 1, 16, 0x20001000, 0x20004000, 0x400e0800, false);
break;
case 0x28090560 : // C
case 0x28190560 : // E
_family = FAMILY_SAM3U;
flashPtr = new EefcFlash(_samba, "ATSAM3U1", 0x80000, 256, 256, 1, 8, 0x20001000, 0x20002000, 0x400e0800, false);
break;
//
// SAM3X
//
case 0x286e0a60 : // 8H
case 0x285e0a60 : // 8E
case 0x284e0a60 : // 8C
_family = FAMILY_SAM3X;
flashPtr = new EefcFlash(_samba, "ATSAM3X8", 0x80000, 2048, 256, 2, 32, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x285b0960 : // 4E
case 0x284b0960 : // 4C
_family = FAMILY_SAM3X;
flashPtr = new EefcFlash(_samba, "ATSAM3X4", 0x80000, 1024, 256, 2, 16, 0x20001000, 0x20008000, 0x400e0a00, false);
break;
//
// SAM3A
//
case 0x283e0A60 : // 8C
_family = FAMILY_SAM3A;
flashPtr = new EefcFlash(_samba, "ATSAM3A8", 0x80000, 2048, 256, 2, 32, 0x20001000, 0x20010000, 0x400e0a00, false);
break;
case 0x283b0960 : // 4C
_family = FAMILY_SAM3A;
flashPtr = new EefcFlash(_samba, "ATSAM3A4", 0x80000, 1024, 256, 2, 16, 0x20001000, 0x20008000, 0x400e0a00, false);
break;
//
// SAM7L
//
case 0x27330740 :
_family = FAMILY_SAM7L;
flashPtr = new EefcFlash(_samba, "ATSAM7L128", 0x100000, 512, 256, 1, 16, 0x2ffb40, 0x300700, 0xffffff60, false);
break;
case 0x27330540 :
_family = FAMILY_SAM7L;
flashPtr = new EefcFlash(_samba, "ATSAM7L64", 0x100000, 256, 256, 1, 8, 0x2ffb40, 0x300700, 0xffffff60, false);
break;
//
// SAM9XE
//
case 0x329aa3a0 :
_family = FAMILY_SAM9XE;
flashPtr = new EefcFlash(_samba, "ATSAM9XE512", 0x200000, 1024, 512, 1, 32, 0x300000, 0x307000, 0xfffffa00, true);
break;
case 0x329a93a0 :
_family = FAMILY_SAM9XE;
flashPtr = new EefcFlash(_samba, "ATSAM9XE256", 0x200000, 512, 512, 1, 16, 0x300000, 0x307000, 0xfffffa00, true);
break;
case 0x329973a0 :
_family = FAMILY_SAM9XE;
flashPtr = new EefcFlash(_samba, "ATSAM9XE128", 0x200000, 256, 512, 1, 8, 0x300000, 0x303000, 0xfffffa00, true);
break;
//
// SAM4E
//
case 0x23cc0ce0:
switch (extChipId)
{
case 0x00120200: // E
case 0x00120201: // C
_family = FAMILY_SAM4E;
flashPtr = new EefcFlash(_samba, "ATSAM4E16", 0x400000, 2048, 512, 1, 128, 0x20001000, 0x20020000, 0x400e0a00, false);
break;
case 0x00120208: // E
case 0x00120209: // C
_family = FAMILY_SAM4E;
flashPtr = new EefcFlash(_samba, "ATSAM4E8", 0x400000, 1024, 512, 1, 64, 0x20001000, 0x20020000, 0x400e0a00, false);
break;
}
break;
//
// SAME70
//
case 0x210d0a00:
_family = FAMILY_SAME70;
flashPtr = new EefcFlash(_samba, "ATSAME70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21020c00:
_family = FAMILY_SAME70;
flashPtr = new EefcFlash(_samba, "ATSAME70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21020e00:
_family = FAMILY_SAME70;
flashPtr = new EefcFlash(_samba, "ATSAME70x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
//
// SAMS70
//
case 0x211d0a00:
_family = FAMILY_SAMS70;
flashPtr = new EefcFlash(_samba, "ATSAMS70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21120c00:
_family = FAMILY_SAMS70;
flashPtr = new EefcFlash(_samba, "ATSAMS70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21120e00:
_family = FAMILY_SAMS70;
flashPtr = new EefcFlash(_samba, "ATSAMS70x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
//
// SAMV70
//
case 0x213d0a00:
_family = FAMILY_SAMV70;
flashPtr = new EefcFlash(_samba, "ATSAMV70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21320c00:
_family = FAMILY_SAMV70;
flashPtr = new EefcFlash(_samba, "ATSAMV70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
//
// SAMV71
//
case 0x212d0a00:
_family = FAMILY_SAMV71;
flashPtr = new EefcFlash(_samba, "ATSAMV71x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21220c00:
_family = FAMILY_SAMV71;
flashPtr = new EefcFlash(_samba, "ATSAMV71x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
case 0x21220e00:
_family = FAMILY_SAMV71;
flashPtr = new EefcFlash(_samba, "ATSAMV71x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false);
break;
//
// No CHIPID devices
//
case 0:
switch (deviceId & 0xffff00ff)
{
//
// SAMD21
//
case 0x10010003: // J15A
case 0x10010008: // G15A
case 0x1001000d: // E15A
case 0x10010021: // J15B
case 0x10010024: // G15B
case 0x10010027: // E15B
case 0x10010056: // E15B WLCSP
case 0x10010063: // E15C WLCSP
_family = FAMILY_SAMD21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x15", 512, 64, 0x20000800, 0x20001000) ;
break;
case 0x10010002: // J16A
case 0x10010007: // G16A
case 0x1001000c: // E16A
case 0x10010020: // J16B
case 0x10010023: // G16B
case 0x10010026: // E16B
case 0x10010055: // E16B WLCSP
case 0x10010062: // E16C WLCSP
_family = FAMILY_SAMD21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x16", 1024, 64, 0x20001000, 0x20002000) ;
break;
case 0x10010001: // J17A
case 0x10010006: // G17A
case 0x1001000b: // E17A
case 0x10010010: // G17A WLCSP
_family = FAMILY_SAMD21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x17", 2048, 64, 0x20002000, 0x20004000) ;
break;
case 0x10010000: // J18A
case 0x10010005: // G18A
case 0x1001000a: // E18A
case 0x1001000f: // G18A WLCSP
_family = FAMILY_SAMD21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x18", 4096, 64, 0x20004000, 0x20008000) ;
break;
//
// SAMR21
//
case 0x1001001e: // E16A
case 0x1001001b: // G16A
_family = FAMILY_SAMR21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x16", 1024, 64, 0x20001000, 0x20002000) ;
break;
case 0x1001001d: // E17A
case 0x1001001a: // G17A
_family = FAMILY_SAMR21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x17", 2048, 64, 0x20002000, 0x20004000) ;
break;
case 0x1001001c: // E18A
case 0x10010019: // G18A
_family = FAMILY_SAMR21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x18", 4096, 64, 0x20004000, 0x20008000) ;
break;
case 0x10010018: // E19A
_family = FAMILY_SAMR21;
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x19", 4096, 64, 0x20004000, 0x20008000) ;
break;
//
// SAML21
//
case 0x1081000d: // E15A
case 0x1081001c: // E15B
_family = FAMILY_SAMD21;
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x15", 512, 64, 0x20000800, 0x20001000) ;
break;
case 0x10810002: // J16A
case 0x10810007: // G16A
case 0x1081000c: // E16A
case 0x10810011: // J16B
case 0x10810016: // G16B
case 0x1081001b: // E16B
_family = FAMILY_SAML21;
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x16", 1024, 64, 0x20001000, 0x20002000) ;
break;
case 0x10810001: // J17A
case 0x10810006: // G17A
case 0x1081000b: // E17A
case 0x10810010: // J17B
case 0x10810015: // G17B
case 0x1081001a: // E17B
_family = FAMILY_SAML21;
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x17", 2048, 64, 0x20002000, 0x20004000) ;
break;
case 0x10810000: // J18A
case 0x10810005: // G18A
case 0x1081000a: // E18A
case 0x1081000f: // J18B
case 0x10810014: // G18B
case 0x10810019: // E18B
_family = FAMILY_SAML21;
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x18", 4096, 64, 0x20004000, 0x20008000) ;
break;
//
// SAMD51
//
case 0x60060006: // J18A
case 0x60060008: // G18A
_family = FAMILY_SAMD51;
flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x18", 512, 512, 0x20004000, 0x20008000) ;
break;
case 0x60060001: // P19A
case 0x60060003: // N19A
case 0x60060005: // J19A
case 0x60060007: // G19A
_family = FAMILY_SAMD51;
flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x19", 1024, 512, 0x20004000, 0x20008000) ;
break;
case 0x60060000: // P20A
case 0x60060002: // N20A
case 0x60060004: // J20A
_family = FAMILY_SAMD51;
flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x20", 2048, 512, 0x20004000, 0x20008000) ;
break;
//
// SAME51
//
case 0x61810003: // J18A
_family = FAMILY_SAME51;
flashPtr = new D5xNvmFlash(_samba, "ATSAME51x18", 512, 512, 0x20004000, 0x20008000) ;
break;
case 0x61810002: // J19A
case 0x61810001: // N19A
_family = FAMILY_SAME51;
flashPtr = new D5xNvmFlash(_samba, "ATSAME51x19", 1024, 512, 0x20004000, 0x20008000) ;
break;
case 0x61810004: // J20A
case 0x61810000: // N20A
_family = FAMILY_SAME51;
flashPtr = new D5xNvmFlash(_samba, "ATSAME51x20", 2048, 512, 0x20004000, 0x20008000) ;
break;
//
// SAME53
//
case 0x61830006: // J18A
_family = FAMILY_SAME53;
flashPtr = new D5xNvmFlash(_samba, "ATSAME53x18", 512, 512, 0x20004000, 0x20008000) ;
break;
case 0x61830005: // J19A
case 0x61830003: // N19A
_family = FAMILY_SAME53;
flashPtr = new D5xNvmFlash(_samba, "ATSAME53x19", 1024, 512, 0x20004000, 0x20008000) ;
break;
case 0x61830004: // J20A
case 0x61830002: // N20A
_family = FAMILY_SAME53;
flashPtr = new D5xNvmFlash(_samba, "ATSAME53x20", 2048, 512, 0x20004000, 0x20008000) ;
break;
//
// SAME54
//
case 0x61840001: // P19A
case 0x61840003: // N19A
_family = FAMILY_SAME54;
flashPtr = new D5xNvmFlash(_samba, "ATSAME54x19", 1024, 512, 0x20004000, 0x20008000) ;
break;
case 0x61840000: // P20A
case 0x61840002: // N20A
_family = FAMILY_SAME54;
flashPtr = new D5xNvmFlash(_samba, "ATSAME54x20", 2048, 512, 0x20004000, 0x20008000) ;
break;
//
// Unknown
//
default:
throw DeviceUnsupportedError();
break;
}
break;
//
// Unsupported device
//
default:
throw DeviceUnsupportedError();
break;
}
_flash = std::unique_ptr<Flash>(flashPtr);
}
void
Device::reset()
{
try
{
switch (_family)
{
case FAMILY_SAMD21:
case FAMILY_SAMR21:
case FAMILY_SAML21:
case FAMILY_SAMD51:
case FAMILY_SAME51:
case FAMILY_SAME53:
case FAMILY_SAME54:
case FAMILY_SAME70:
case FAMILY_SAMS70:
case FAMILY_SAMV70:
case FAMILY_SAMV71:
_samba.writeWord(0xE000ED0C, 0x05FA0004);
break;
case FAMILY_SAM3X:
case FAMILY_SAM3S:
case FAMILY_SAM3A:
_samba.writeWord(0x400E1A00, 0xA500000D);
break;
case FAMILY_SAM3U:
_samba.writeWord(0x400E1200, 0xA500000D);
break;
case FAMILY_SAM3N:
case FAMILY_SAM4S:
_samba.writeWord(0x400E1400, 0xA500000D);
break;
case FAMILY_SAM4E:
_samba.writeWord(0x400E1800, 0xA500000D);
break;
case FAMILY_SAM7S:
case FAMILY_SAM7SE:
case FAMILY_SAM7X:
case FAMILY_SAM7XC:
case FAMILY_SAM7L:
case FAMILY_SAM9XE:
_samba.writeWord(0xFFFFFD00, 0xA500000D);
break;
default:
break;
}
}
catch (std::exception& expected)
{ // writeWord will most likely throw an exception when the CPU is reset
}
}

104
lib/bossac/src/Device.h Normal file
View file

@ -0,0 +1,104 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _DEVICE_H
#define _DEVICE_H
#include <exception>
#include "Samba.h"
#include "Flash.h"
class DeviceUnsupportedError : public std::exception
{
public:
DeviceUnsupportedError() : exception() {};
const char* what() const throw() { return "Device unsupported"; }
};
class Device
{
public:
enum Family {
FAMILY_NONE,
FAMILY_SAM7S,
FAMILY_SAM7SE,
FAMILY_SAM7X,
FAMILY_SAM7XC,
FAMILY_SAM7L,
FAMILY_SAM3N,
FAMILY_SAM3S,
FAMILY_SAM3U,
FAMILY_SAM3X,
FAMILY_SAM3A,
FAMILY_SAM4S,
FAMILY_SAM4E,
FAMILY_SAM9XE,
FAMILY_SAMD21,
FAMILY_SAMR21,
FAMILY_SAML21,
FAMILY_SAMD51,
FAMILY_SAME51,
FAMILY_SAME53,
FAMILY_SAME54,
FAMILY_SAME70,
FAMILY_SAMS70,
FAMILY_SAMV70,
FAMILY_SAMV71,
};
Device(Samba& samba) : _samba(samba), _flash(nullptr), _family(FAMILY_NONE) {}
virtual ~Device() {}
void create();
Family getFamily() { return _family; }
typedef std::unique_ptr<Flash> const FlashPtr;
FlashPtr& getFlash() { return _flash; }
void reset();
private:
Samba& _samba;
std::unique_ptr<Flash> _flash;
Family _family;
void readChipId(uint32_t& chipId, uint32_t& extChipId);
};
#endif // _DEVICE_H

View file

@ -0,0 +1,363 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "EefcFlash.h"
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#define EEFC_KEY 0x5a
#define EEFC0_FMR (_regs + 0x00)
#define EEFC0_FCR (_regs + 0x04)
#define EEFC0_FSR (_regs + 0x08)
#define EEFC0_FRR (_regs + 0x0C)
#define EEFC1_FMR (_regs + 0x200)
#define EEFC1_FCR (_regs + 0x204)
#define EEFC1_FSR (_regs + 0x208)
#define EEFC1_FRR (_regs + 0x20C)
#define EEFC_FCMD_GETD 0x0
#define EEFC_FCMD_WP 0x1
#define EEFC_FCMD_WPL 0x2
#define EEFC_FCMD_EWP 0x3
#define EEFC_FCMD_EWPL 0x4
#define EEFC_FCMD_EA 0x5
#define EEFC_FCMD_EPA 0x7
#define EEFC_FCMD_SLB 0x8
#define EEFC_FCMD_CLB 0x9
#define EEFC_FCMD_GLB 0xa
#define EEFC_FCMD_SGPB 0xb
#define EEFC_FCMD_CGPB 0xc
#define EEFC_FCMD_GGPB 0xd
const uint32_t
EefcFlash::PagesPerErase = 8;
EefcFlash::EefcFlash(Samba& samba,
const std::string& name,
uint32_t addr,
uint32_t pages,
uint32_t size,
uint32_t planes,
uint32_t lockRegions,
uint32_t user,
uint32_t stack,
uint32_t regs,
bool canBrownout)
: Flash(samba, name, addr, pages, size, planes, lockRegions, user, stack),
_regs(regs), _canBrownout(canBrownout), _eraseAuto(true)
{
assert(planes == 1 || planes == 2);
assert(pages <= 4096);
assert(lockRegions <= 256);
// SAM3 Errata (FWS must be 6)
_samba.writeWord(EEFC0_FMR, 0x6 << 8);
if (planes == 2)
_samba.writeWord(EEFC1_FMR, 0x6 << 8);
}
EefcFlash::~EefcFlash()
{
}
void
EefcFlash::eraseAll(uint32_t offset)
{
// Do a full chip erase if the offset is 0
if (offset == 0)
{
waitFSR();
writeFCR0(EEFC_FCMD_EA, 0);
if (_planes == 2)
{
waitFSR();
writeFCR1(EEFC_FCMD_EA, 0);
}
// Erase all can take an exceptionally long time on some devices
// so wait on FSR for up to 30 seconds
waitFSR(30);
}
// Else we must do it by pages
else
{
// Offset must be on an erase page boundary
if (offset % (_size * PagesPerErase))
throw FlashEraseError();
// Erase each PagesPerErase set of pages
for (uint32_t pageNum = offset / _size; pageNum < _pages; pageNum += PagesPerErase)
{
if (_planes == 1 || pageNum < _pages / 2)
{
waitFSR();
writeFCR0(EEFC_FCMD_EPA, pageNum | 0x1);
}
else
{
waitFSR();
writeFCR1(EEFC_FCMD_EPA, (pageNum % (_pages / 2)) | 0x1);
}
}
}
}
void
EefcFlash::eraseAuto(bool enable)
{
_eraseAuto = enable;
}
std::vector<bool>
EefcFlash::getLockRegions()
{
std::vector<bool> regions(_lockRegions);
uint32_t frr;
uint32_t bit;
waitFSR();
for (uint32_t region = 0; region < _lockRegions; region++)
{
if (_planes == 2 && region >= _lockRegions / 2)
{
bit = region - _lockRegions / 2;
writeFCR1(EEFC_FCMD_GLB, 0);
waitFSR();
frr = readFRR1();
while (bit >= 32)
{
frr = readFRR1();
bit -= 32;
}
regions[region] = (frr & (1 << bit)) != 0;
}
else
{
bit = region;
writeFCR0(EEFC_FCMD_GLB, 0);
waitFSR();
frr = readFRR0();
while (bit >= 32)
{
frr = readFRR0();
bit -= 32;
}
regions[region] = (frr & (1 << bit)) != 0;
}
}
return regions;
}
bool
EefcFlash::getSecurity()
{
waitFSR();
writeFCR0(EEFC_FCMD_GGPB, 0);
waitFSR();
return (readFRR0() & (1 << 0));
}
bool
EefcFlash::getBod()
{
if (!_canBrownout)
return false;
waitFSR();
writeFCR0(EEFC_FCMD_GGPB, 0);
waitFSR();
return (readFRR0() & (1 << 1));
}
bool
EefcFlash::getBor()
{
if (!_canBrownout)
return false;
waitFSR();
writeFCR0(EEFC_FCMD_GGPB, 0);
waitFSR();
return (readFRR0() & (1 << 2));
}
bool
EefcFlash::getBootFlash()
{
waitFSR();
writeFCR0(EEFC_FCMD_GGPB, 0);
waitFSR();
return (readFRR0() & (1 << (_canBrownout ? 3 : 1)));
}
void
EefcFlash::writeOptions()
{
if (canBootFlash() && _bootFlash.isDirty() && _bootFlash.get() != getBootFlash())
{
waitFSR();
writeFCR0(_bootFlash.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, (canBod() ? 3 : 1));
}
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
{
waitFSR();
writeFCR0(_bor.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, 2);
}
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
{
waitFSR();
writeFCR0(_bod.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, 1);
}
if (_regions.isDirty())
{
uint32_t page;
std::vector<bool> current;
if (_regions.get().size() >= _lockRegions)
throw FlashRegionError();
current = getLockRegions();
for (uint32_t region = 0; region < _lockRegions; region++)
{
if (_regions.get()[region] != current[region])
{
if (_planes == 2 && region >= _lockRegions / 2)
{
page = (region - _lockRegions / 2) * _pages / _lockRegions;
waitFSR();
writeFCR1(_regions.get()[region] ? EEFC_FCMD_SLB : EEFC_FCMD_CLB, page);
}
else
{
page = region * _pages / _lockRegions;
waitFSR();
writeFCR0(_regions.get()[region] ? EEFC_FCMD_SLB : EEFC_FCMD_CLB, page);
}
}
}
}
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
{
waitFSR();
writeFCR0(EEFC_FCMD_SGPB, 0);
}
}
void
EefcFlash::writePage(uint32_t page)
{
if (page >= _pages)
throw FlashPageError();
_wordCopy.setDstAddr(_addr + page * _size);
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_onBufferA = !_onBufferA;
waitFSR();
_wordCopy.runv();
if (_planes == 2 && page >= _pages / 2)
writeFCR1(_eraseAuto ? EEFC_FCMD_EWP : EEFC_FCMD_WP, page - _pages / 2);
else
writeFCR0(_eraseAuto ? EEFC_FCMD_EWP : EEFC_FCMD_WP, page);
}
void
EefcFlash::readPage(uint32_t page, uint8_t* data)
{
if (page >= _pages)
throw FlashPageError();
// The SAM3 firmware has a bug where it returns all zeros for reads
// directly from the flash so instead, we copy the flash page to
// SRAM and read it from there.
_wordCopy.setDstAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_wordCopy.setSrcAddr(_addr + page * _size);
waitFSR();
_wordCopy.runv();
_samba.read(_onBufferA ? _pageBufferA : _pageBufferB, data, _size);
}
void
EefcFlash::waitFSR(int seconds)
{
int tries = seconds * 1000;
uint32_t fsr0;
uint32_t fsr1 = 0x1;
while (tries-- > 0)
{
fsr0 = _samba.readWord(EEFC0_FSR);
if (fsr0 & 0x2)
throw FlashCmdError();
if (fsr0 & 0x4)
throw FlashLockError();
if (_planes == 2)
{
fsr1 = _samba.readWord(EEFC1_FSR);
if (fsr1 & 0x2)
throw FlashCmdError();
if (fsr1 & 0x4)
throw FlashLockError();
}
if (fsr0 & fsr1 & 0x1)
break;
usleep(1000);
}
if (tries == 0)
throw FlashTimeoutError();
}
void
EefcFlash::writeFCR0(uint8_t cmd, uint32_t arg)
{
_samba.writeWord(EEFC0_FCR, (EEFC_KEY << 24) | (arg << 8) | cmd);
}
void
EefcFlash::writeFCR1(uint8_t cmd, uint32_t arg)
{
_samba.writeWord(EEFC1_FCR, (EEFC_KEY << 24) | (arg << 8) | cmd);
}
uint32_t
EefcFlash::readFRR0()
{
return _samba.readWord(EEFC0_FRR);
}
uint32_t
EefcFlash::readFRR1()
{
return _samba.readWord(EEFC1_FRR);
}

View file

@ -0,0 +1,88 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _EEFCFLASH_H
#define _EEFCFLASH_H
#include <stdint.h>
#include <exception>
#include "Flash.h"
class EefcFlash : public Flash
{
public:
EefcFlash(Samba& samba,
const std::string& name,
uint32_t addr,
uint32_t pages,
uint32_t size,
uint32_t planes,
uint32_t lockRegions,
uint32_t user,
uint32_t stack,
uint32_t regs,
bool canBrownout);
virtual ~EefcFlash();
void eraseAll(uint32_t offset);
void eraseAuto(bool enable);
std::vector<bool> getLockRegions();
bool getSecurity();
bool getBod();
bool canBod() { return _canBrownout; }
bool getBor();
bool canBor() { return _canBrownout; }
bool getBootFlash();
bool canBootFlash() { return true; }
void writeOptions();
void writePage(uint32_t page);
void readPage(uint32_t page, uint8_t* data);
static const uint32_t PagesPerErase;
private:
uint32_t _regs;
bool _canBrownout;
bool _eraseAuto;
void waitFSR(int seconds = 1);
void writeFCR0(uint8_t cmd, uint32_t arg);
void writeFCR1(uint8_t cmd, uint32_t arg);
uint32_t readFRR0();
uint32_t readFRR1();
};
#endif // _EEFCFLASH_H

295
lib/bossac/src/EfcFlash.cpp Normal file
View file

@ -0,0 +1,295 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "EfcFlash.h"
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#define EFC_KEY 0x5a
#define EFC0_FMR 0xffffff60
#define EFC0_FCR 0xffffff64
#define EFC0_FSR 0xffffff68
#define EFC1_FMR 0xffffff70
#define EFC1_FCR 0xffffff74
#define EFC1_FSR 0xffffff78
#define EFC_FCMD_WP 0x1
#define EFC_FCMD_SLB 0x2
#define EFC_FCMD_WPL 0x3
#define EFC_FCMD_CLB 0x4
#define EFC_FCMD_EA 0x8
#define EFC_FCMD_SGPB 0xb
#define EFC_FCMD_CGPB 0xd
#define EFC_FCMD_SSB 0xf
EfcFlash::EfcFlash(Samba& samba,
const std::string& name,
uint32_t addr,
uint32_t pages,
uint32_t size,
uint32_t planes,
uint32_t lockRegions,
uint32_t user,
uint32_t stack,
bool canBootFlash)
: Flash(samba, name, addr, pages, size, planes, lockRegions, user, stack),
_canBootFlash(canBootFlash)
{
assert(planes == 1 || planes == 2);
assert(pages <= planes * 1024);
assert(lockRegions <= 32);
eraseAuto(true);
}
EfcFlash::~EfcFlash()
{
}
void
EfcFlash::eraseAll(uint32_t offset)
{
if (offset != 0)
throw FlashEraseError();
waitFSR();
writeFCR0(EFC_FCMD_EA, 0);
if (_planes == 2)
{
waitFSR();
writeFCR0(EFC_FCMD_EA, _pages / 2);
}
}
void
EfcFlash::eraseAuto(bool enable)
{
uint32_t fmr;
waitFSR();
fmr = _samba.readWord(EFC0_FMR);
if (enable)
fmr &= ~(1 << 7);
else
fmr |= (1 << 7);
_samba.writeWord(EFC0_FMR, fmr);
if (_planes == 2)
{
waitFSR();
_samba.writeWord(EFC1_FMR, fmr);
}
}
std::vector<bool>
EfcFlash::getLockRegions()
{
std::vector<bool> regions(_lockRegions);
uint32_t fsr0;
uint32_t fsr1;
fsr0 = readFSR0();
if (_planes == 2)
fsr1 = readFSR1();
else
fsr1 = 0;
for (uint32_t region = 0; region < _lockRegions; region++)
{
if (_planes == 2 && region >= _lockRegions / 2)
regions[region] = (fsr1 & (1 << (16 + region - _lockRegions / 2))) != 0;
else
regions[region] = (fsr0 & (1 << (16 + region))) != 0;
}
return regions;
}
bool
EfcFlash::getSecurity()
{
return (readFSR0() & (1 << 4));
}
bool
EfcFlash::getBod()
{
return (readFSR0() & (1 << 8));
}
bool
EfcFlash::getBor()
{
return (readFSR0() & (2 << 8));
}
bool
EfcFlash::getBootFlash()
{
if (!_canBootFlash)
return false;
return (readFSR0() & (1 << 10));
}
void
EfcFlash::writeOptions()
{
if (canBootFlash() && _bootFlash.isDirty() && _bootFlash.get() != getBootFlash())
{
waitFSR();
writeFCR0(_bootFlash.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 2);
}
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
{
waitFSR();
writeFCR0(_bor.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 1);
}
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
{
waitFSR();
writeFCR0(_bod.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 0);
}
if (_regions.isDirty())
{
uint32_t page;
std::vector<bool> current;
current = getLockRegions();
for (uint32_t region = 0; region < _regions.get().size(); region++)
{
if (_regions.get()[region] != current[region])
{
if (_planes == 2 && region >= _lockRegions / 2)
{
page = (region - _lockRegions / 2) * _pages / _lockRegions;
waitFSR();
writeFCR1(_regions.get()[region] ? EFC_FCMD_SLB : EFC_FCMD_CLB, page);
}
else
{
page = region * _pages / _lockRegions;
waitFSR();
writeFCR0(_regions.get()[region] ? EFC_FCMD_SLB : EFC_FCMD_CLB, page);
}
}
}
}
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
{
waitFSR();
writeFCR0(EFC_FCMD_SSB, 0);
}
}
void
EfcFlash::writePage(uint32_t page)
{
if (page >= _pages)
throw FlashPageError();
_wordCopy.setDstAddr(_addr + page * _size);
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
_onBufferA = !_onBufferA;
waitFSR();
_wordCopy.run();
if (_planes == 2 && page >= _pages / 2)
writeFCR1(EFC_FCMD_WP, page - _pages / 2);
else
writeFCR0(EFC_FCMD_WP, page);
}
void
EfcFlash::readPage(uint32_t page, uint8_t* data)
{
if (page >= _pages)
throw FlashPageError();
waitFSR();
_samba.read(_addr + page * _size, data, _size);
}
void
EfcFlash::waitFSR(int seconds)
{
int tries = seconds * 1000;
uint32_t fsr0;
uint32_t fsr1 = 0x1;
while (tries-- > 0)
{
fsr0 = readFSR0();
if (fsr0 & 0x2)
throw FlashCmdError();
if (fsr0 & 0x4)
throw FlashLockError();
if (_planes == 2)
{
fsr1 = readFSR1();
if (fsr1 & 0x2)
throw FlashCmdError();
if (fsr1 & 0x4)
throw FlashLockError();
}
if (fsr0 & fsr1 & 0x1)
break;
usleep(1000);
}
if (tries == 0)
throw FlashTimeoutError();
}
void
EfcFlash::writeFCR0(uint8_t cmd, uint32_t arg)
{
_samba.writeWord(EFC0_FCR, (EFC_KEY << 24) | (arg << 8) | cmd);
}
void
EfcFlash::writeFCR1(uint8_t cmd, uint32_t arg)
{
_samba.writeWord(EFC1_FCR, (EFC_KEY << 24) | (arg << 8) | cmd);
}
uint32_t
EfcFlash::readFSR0()
{
return _samba.readWord(EFC0_FSR);
}
uint32_t
EfcFlash::readFSR1()
{
return _samba.readWord(EFC1_FSR);
}

83
lib/bossac/src/EfcFlash.h Normal file
View file

@ -0,0 +1,83 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _EFCFLASH_H
#define _EFCFLASH_H
#include <stdint.h>
#include <exception>
#include "Flash.h"
class EfcFlash : public Flash
{
public:
EfcFlash(Samba& samba,
const std::string& name,
uint32_t addr,
uint32_t pages,
uint32_t size,
uint32_t planes,
uint32_t lockRegions,
uint32_t user,
uint32_t stack,
bool canBootFlash);
virtual ~EfcFlash();
void eraseAll(uint32_t offset);
void eraseAuto(bool enable);
std::vector<bool> getLockRegions();
bool getSecurity();
bool getBod();
bool canBod() { return true; }
bool getBor();
bool canBor() { return true; }
bool getBootFlash();
bool canBootFlash() { return _canBootFlash; }
void writeOptions();
void writePage(uint32_t page);
void readPage(uint32_t page, uint8_t* data);
private:
bool _canBootFlash;
void waitFSR(int seconds = 1);
void writeFCR0(uint8_t cmd, uint32_t arg);
void writeFCR1(uint8_t cmd, uint32_t arg);
uint32_t readFSR0();
uint32_t readFSR1();
};
#endif // _EFCFLASH_H

View file

@ -0,0 +1,94 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _FILEERROR_H
#define _FILEERROR_H
#include <exception>
#include <errno.h>
#include <string.h>
#include "Flash.h"
#include "Samba.h"
class FileError : public std::exception
{
public:
FileError() : std::exception() {}
};
class FileOpenError : public FileError
{
public:
FileOpenError() : FileError(), _errnum(0) {};
FileOpenError(int errnum) : FileError(), _errnum(errnum) {};
const char* what() const throw()
{
if (_errnum == 0)
return "Unable to open file";
else
return strerror(_errnum);
}
private:
int _errnum;
};
class FileIoError : public FileError
{
public:
FileIoError() : FileError(), _errnum(0) {};
FileIoError(int errnum) : FileError(), _errnum(errnum) {};
const char* what() const throw()
{
if (_errnum == 0)
return "File I/O operation failed";
else
return strerror(_errnum);
}
private:
int _errnum;
};
class FileShortError : public FileError
{
public:
FileShortError() : FileError() {};
const char* what() const throw()
{
return "Operation ended with a short write";
}
};
class FileSizeError : public FileError
{
public:
FileSizeError() {};
const char* what() const throw() { return "File operation exceeds flash size"; }
};
#endif // _FILEERROR_H

106
lib/bossac/src/Flash.cpp Normal file
View file

@ -0,0 +1,106 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "Flash.h"
#include <assert.h>
Flash::Flash(Samba& samba,
const std::string& name,
uint32_t addr,
uint32_t pages,
uint32_t size,
uint32_t planes,
uint32_t lockRegions,
uint32_t user,
uint32_t stack)
: _samba(samba), _name(name), _addr(addr), _pages(pages), _size(size),
_planes(planes), _lockRegions(lockRegions), _user(user), _wordCopy(samba, user)
{
assert((size & (size - 1)) == 0);
assert((pages & (pages - 1)) == 0);
assert((lockRegions & (lockRegions - 1)) == 0);
_wordCopy.setWords(size / sizeof(uint32_t));
_wordCopy.setStack(stack);
_onBufferA = true;
// page buffers will have the size of a physical page and will be situated right after the applet
_pageBufferA = ((_user + _wordCopy.size() + 3) / 4) * 4; // we need to avoid non 32bits aligned access on Cortex-M0+
_pageBufferB = _pageBufferA + size;
}
void
Flash::setLockRegions(const std::vector<bool>& regions)
{
if (regions.size() > _lockRegions)
throw FlashRegionError();
_regions.set(regions);
}
void
Flash::setSecurity()
{
_security.set(true);
}
void
Flash::setBor(bool enable)
{
if (canBor())
_bor.set(enable);
}
void
Flash::setBod(bool enable)
{
if (canBod())
_bod.set(enable);
}
void
Flash::setBootFlash(bool enable)
{
if (canBootFlash())
_bootFlash.set(enable);
}
void
Flash::loadBuffer(const uint8_t* data, uint16_t bufferSize)
{
_samba.write(_onBufferA ? _pageBufferA : _pageBufferB, data, bufferSize);
}
void
Flash::writeBuffer(uint32_t dst_addr, uint32_t size)
{
_samba.writeBuffer(_onBufferA ? _pageBufferA : _pageBufferB, dst_addr + _addr, size);
}

180
lib/bossac/src/Flash.h Normal file
View file

@ -0,0 +1,180 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _FLASH_H
#define _FLASH_H
#include <stdint.h>
#include <vector>
#include <memory>
#include <exception>
#include "Samba.h"
#include "WordCopyApplet.h"
class FlashPageError : public std::exception
{
public:
FlashPageError() : exception() {};
const char* what() const throw() { return "Invalid flash page"; }
};
class FlashRegionError : public std::exception
{
public:
FlashRegionError() : exception() {};
const char* what() const throw() { return "Invalid lock region"; }
};
class FlashLockError : public std::exception
{
public:
FlashLockError() : exception() {};
const char* what() const throw() { return "Flash page is locked"; }
};
class FlashCmdError : public std::exception
{
public:
FlashCmdError() : exception() {};
const char* what() const throw() { return "Flash command failed"; }
};
class FlashTimeoutError : public std::exception
{
public:
FlashTimeoutError() : exception() {};
const char* what() const throw() { return "Flash command timeout"; }
};
class BootFlashError : public std::exception
{
public:
BootFlashError() : exception() {};
const char* what() const throw() { return "Unable to clear boot flash for this device"; }
};
class FlashEraseError : public std::exception
{
public:
FlashEraseError() : exception() {};
const char* what() const throw() { return "Flash erase failed"; }
};
template<class T>
class FlashOption
{
public:
FlashOption() : _dirty(false) {}
virtual ~FlashOption() {}
void set(const T& value) { _value = value; _dirty = true; }
const T& get() { return _value; }
bool isDirty() { return _dirty; }
private:
T _value;
bool _dirty;
};
class Flash
{
public:
Flash(Samba& samba,
const std::string& name,
uint32_t addr, // Flash base address
uint32_t pages, // Number of pages
uint32_t size, // Page size in bytes
uint32_t planes, // Number of flash planes
uint32_t lockRegions, // Number of flash lock regions
uint32_t user, // Address in SRAM where the applet and buffers will be placed
uint32_t stack); // Address in SRAM where the applet stack will be placed
virtual ~Flash() {}
const std::string& name() { return _name; }
virtual uint32_t address() { return _addr; }
virtual uint32_t pageSize() { return _size; }
virtual uint32_t numPages() { return _pages; }
virtual uint32_t numPlanes() { return _planes; }
virtual uint32_t totalSize() { return _size * _pages; }
virtual uint32_t lockRegions() { return _lockRegions; }
virtual void eraseAll(uint32_t offset) = 0;
virtual void eraseAuto(bool enable) = 0;
virtual std::vector<bool> getLockRegions() = 0;
virtual void setLockRegions(const std::vector<bool>& regions);
virtual bool getSecurity() = 0;
virtual void setSecurity();
virtual bool getBod() = 0;
virtual void setBod(bool enable);
virtual bool canBod() = 0;
virtual bool getBor() = 0;
virtual void setBor(bool enable);
virtual bool canBor() = 0;
virtual bool getBootFlash() = 0;
virtual void setBootFlash(bool enable);
virtual bool canBootFlash() = 0;
virtual void writeOptions() = 0;
virtual void writePage(uint32_t page) = 0;
virtual void readPage(uint32_t page, uint8_t* data) = 0;
virtual void writeBuffer(uint32_t dst_addr, uint32_t size);
virtual void loadBuffer(const uint8_t* data, uint16_t size);
protected:
Samba& _samba;
std::string _name;
uint32_t _addr;
uint32_t _pages;
uint32_t _size;
uint32_t _planes;
uint32_t _lockRegions;
uint32_t _user;
WordCopyApplet _wordCopy;
FlashOption<bool> _bootFlash;
FlashOption< std::vector<bool> > _regions;
FlashOption<bool> _bod;
FlashOption<bool> _bor;
FlashOption<bool> _security;
bool _onBufferA;
uint32_t _pageBufferA;
uint32_t _pageBufferB;
};
#endif // _FLASH_H

373
lib/bossac/src/Flasher.cpp Normal file
View file

@ -0,0 +1,373 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include <string>
#include <exception>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "Flasher.h"
using namespace std;
void
FlasherInfo::print()
{
bool first;
printf("Device : %s\n", name.c_str());
printf("Version : %s\n", version.c_str());
printf("Address : 0x%x\n", address);
printf("Pages : %d\n", numPages);
printf("Page Size : %d bytes\n", pageSize);
printf("Total Size : %dKB\n", totalSize / 1024);
printf("Planes : %d\n", numPlanes);
printf("Lock Regions : %zd\n", lockRegions.size());
printf("Locked : ");
first = true;
for (uint32_t region = 0; region < lockRegions.size(); region++)
{
if (lockRegions[region])
{
printf("%s%d", first ? "" : ",", region);
first = false;
}
}
printf("%s\n", first ? "none" : "");
printf("Security : %s\n", security ? "true" : "false");
if (canBootFlash)
printf("Boot Flash : %s\n", bootFlash ? "true" : "false");
if (canBod)
printf("BOD : %s\n", bod ? "true" : "false");
if (canBor)
printf("BOR : %s\n", bor ? "true" : "false");
}
void
Flasher::erase(uint32_t foffset)
{
_observer.onStatus("Erase flash\n");
_flash->eraseAll(foffset);
_flash->eraseAuto(false);
}
void
Flasher::write(const char* filename, uint32_t foffset)
{
FILE* infile;
uint32_t pageSize = _flash->pageSize();
uint32_t pageNum = 0;
uint32_t numPages;
long fsize;
size_t fbytes;
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
throw FlashOffsetError();
infile = fopen(filename, "rb");
if (!infile)
throw FileOpenError(errno);
try
{
if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0)
throw FileIoError(errno);
rewind(infile);
numPages = (fsize + pageSize - 1) / pageSize;
if (numPages > _flash->numPages())
throw FileSizeError();
_observer.onStatus("Write %ld bytes to flash (%u pages)\n", fsize, numPages);
if (_samba.canWriteBuffer())
{
uint32_t offset = 0;
uint32_t bufferSize = _samba.writeBufferSize();
uint8_t buffer[bufferSize];
while ((fbytes = fread(buffer, 1, bufferSize, infile)) > 0)
{
_observer.onProgress(offset / pageSize, numPages);
if (fbytes < bufferSize)
{
memset(buffer + fbytes, 0, bufferSize - fbytes);
fbytes = (fbytes + pageSize - 1) / pageSize * pageSize;
}
_flash->loadBuffer(buffer, fbytes);
_flash->writeBuffer(foffset + offset, fbytes);
offset += fbytes;
}
}
else
{
uint8_t buffer[pageSize];
uint32_t pageOffset = foffset / pageSize;
while ((fbytes = fread(buffer, 1, pageSize, infile)) > 0)
{
_observer.onProgress(pageNum, numPages);
_flash->loadBuffer(buffer, fbytes);
_flash->writePage(pageOffset + pageNum);
pageNum++;
if (pageNum == numPages || fbytes != pageSize)
break;
}
}
}
catch(...)
{
fclose(infile);
throw;
}
fclose(infile);
_observer.onProgress(numPages, numPages);
}
bool
Flasher::verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset)
{
FILE* infile;
uint32_t pageSize = _flash->pageSize();
uint8_t bufferA[pageSize];
uint8_t bufferB[pageSize];
uint32_t pageNum = 0;
uint32_t numPages;
uint32_t pageOffset;
uint32_t byteErrors = 0;
uint16_t calcCrc = 0;
uint16_t flashCrc;
long fsize;
size_t fbytes;
pageErrors = 0;
totalErrors = 0;
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
throw FlashOffsetError();
pageOffset = foffset / pageSize;
infile = fopen(filename, "rb");
if (!infile)
throw FileOpenError(errno);
try
{
if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0)
throw FileIoError(errno);
rewind(infile);
numPages = (fsize + pageSize - 1) / pageSize;
if (numPages > _flash->numPages())
throw FileSizeError();
_observer.onStatus("Verify %ld bytes of flash\n", fsize);
while ((fbytes = fread(bufferA, 1, pageSize, infile)) > 0)
{
byteErrors = 0;
_observer.onProgress(pageNum, numPages);
if (_samba.canChecksumBuffer())
{
for (uint32_t i = 0; i < fbytes; i++)
calcCrc = _samba.checksumCalc(bufferA[i], calcCrc);
flashCrc = _samba.checksumBuffer((pageOffset + pageNum) * pageSize, fbytes);
if (flashCrc != calcCrc)
{
_flash->readPage(pageOffset + pageNum, bufferB);
for (uint32_t i = 0; i < fbytes; i++)
{
if (bufferA[i] != bufferB[i])
byteErrors++;
}
}
}
else
{
_flash->readPage(pageOffset + pageNum, bufferB);
for (uint32_t i = 0; i < fbytes; i++)
{
if (bufferA[i] != bufferB[i])
byteErrors++;
}
}
if (byteErrors != 0)
{
pageErrors++;
totalErrors += byteErrors;
}
pageNum++;
if (pageNum == numPages || fbytes != pageSize)
break;
}
}
catch(...)
{
fclose(infile);
throw;
}
fclose(infile);
_observer.onProgress(numPages, numPages);
if (pageErrors != 0)
return false;
return true;
}
void
Flasher::read(const char* filename, uint32_t fsize, uint32_t foffset)
{
FILE* outfile;
uint32_t pageSize = _flash->pageSize();
uint8_t buffer[pageSize];
uint32_t pageNum = 0;
uint32_t pageOffset;
uint32_t numPages;
size_t fbytes;
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
throw FlashOffsetError();
pageOffset = foffset / pageSize;
if (fsize == 0)
fsize = pageSize * (_flash->numPages() - pageOffset);
numPages = (fsize + pageSize - 1) / pageSize;
if (pageOffset + numPages > _flash->numPages())
throw FileSizeError();
outfile = fopen(filename, "wb");
if (!outfile)
throw FileOpenError(errno);
_observer.onStatus("Read %d bytes from flash\n", fsize);
try
{
for (pageNum = 0; pageNum < numPages; pageNum++)
{
_observer.onProgress(pageNum, numPages);
_flash->readPage(pageOffset + pageNum, buffer);
if (pageNum == numPages - 1 && fsize % pageSize > 0)
pageSize = fsize % pageSize;
fbytes = fwrite(buffer, 1, pageSize, outfile);
if (fbytes != pageSize)
throw FileShortError();
}
}
catch(...)
{
fclose(outfile);
throw;
}
_observer.onProgress(numPages, numPages);
fclose(outfile);
}
void
Flasher::lock(string& regionArg, bool enable)
{
if (regionArg.empty())
{
_observer.onStatus("%s all regions\n", enable ? "Lock" : "Unlock");
std::vector<bool> regions(_flash->lockRegions(), enable);
_flash->setLockRegions(regions);
}
else
{
size_t pos = 0;
size_t delim;
uint32_t region;
string sub;
std::vector<bool> regions = _flash->getLockRegions();
do
{
delim = regionArg.find(',', pos);
sub = regionArg.substr(pos, delim - pos);
region = strtol(sub.c_str(), NULL, 0);
_observer.onStatus("%s region %d\n", enable ? "Lock" : "Unlock", region);
regions[region] = enable;
pos = delim + 1;
} while (delim != string::npos);
_flash->setLockRegions(regions);
}
}
void
Flasher::info(FlasherInfo& info)
{
info.name = _flash->name();
info.version = _samba.version();
info.address = _flash->address();
info.numPages = _flash->numPages();
info.pageSize = _flash->pageSize();
info.totalSize = _flash->numPages() * _flash->pageSize();
info.numPlanes = _flash->numPlanes();
info.security = _flash->getSecurity();
info.bootFlash = _flash->getBootFlash();
info.bod = _flash->getBod();
info.bor = _flash->getBor();
info.canBootFlash = _flash->canBootFlash();
info.canBod = _flash->canBod();
info.canBor = _flash->canBor();
info.canChipErase = _samba.canChipErase();
info.canWriteBuffer = _samba.canWriteBuffer();
info.canChecksumBuffer = _samba.canChecksumBuffer();
info.lockRegions = _flash->getLockRegions();
}

110
lib/bossac/src/Flasher.h Normal file
View file

@ -0,0 +1,110 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _FLASHER_H
#define _FLASHER_H
#include <string>
#include <exception>
#include <vector>
#include "Device.h"
#include "Flash.h"
#include "Samba.h"
#include "FileError.h"
class FlashOffsetError : public std::exception
{
public:
FlashOffsetError() : std::exception() {};
virtual const char* what() const throw() { return "Flash offset is invalid"; }
};
class FlasherObserver
{
public:
FlasherObserver() {}
virtual ~FlasherObserver() {}
virtual void onStatus(const char *message, ...) = 0;
virtual void onProgress(int num, int div) = 0;
};
class FlasherInfo
{
public:
FlasherInfo() {}
virtual ~FlasherInfo() {}
void print();
std::string name;
uint32_t chipId;
uint32_t extChipId;
std::string version;
uint32_t address;
uint32_t numPages;
uint32_t pageSize;
uint32_t totalSize;
uint32_t numPlanes;
bool security;
bool bootFlash;
bool bod;
bool bor;
bool canBootFlash;
bool canBod;
bool canBor;
bool canChipErase;
bool canWriteBuffer;
bool canChecksumBuffer;
std::vector<bool> lockRegions;
};
class Flasher
{
public:
Flasher(Samba& samba, Device& device, FlasherObserver& observer) : _samba(samba), _flash(device.getFlash()), _observer(observer) {}
virtual ~Flasher() {}
void erase(uint32_t foffset);
void write(const char* filename, uint32_t foffset = 0);
bool verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset = 0);
void read(const char* filename, uint32_t fsize, uint32_t foffset = 0);
void lock(std::string& regionArg, bool enable);
void info(FlasherInfo& info);
private:
Samba& _samba;
Device::FlashPtr& _flash;
FlasherObserver& _observer;
};
#endif // _FLASHER_H

View file

@ -0,0 +1,109 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "LinuxPortFactory.h"
#include "PosixSerialPort.h"
#include <string.h>
#include <stdio.h>
#include <string>
LinuxPortFactory::LinuxPortFactory()
{
_dir = opendir("/dev");
}
LinuxPortFactory::~LinuxPortFactory()
{
if (_dir)
closedir(_dir);
}
SerialPort::Ptr
LinuxPortFactory::create(const std::string& name)
{
bool isUsb = false;
if (name.find("ttyUSB") != std::string::npos ||
name.find("ttyACM") != std::string::npos)
isUsb = true;
return create(name, isUsb);
}
SerialPort::Ptr
LinuxPortFactory::create(const std::string& name, bool isUsb)
{
return SerialPort::Ptr(new PosixSerialPort(name, isUsb));
}
std::string
LinuxPortFactory::begin()
{
if (!_dir)
return end();
rewinddir(_dir);
return next();
}
std::string
LinuxPortFactory::next()
{
struct dirent* entry;
if (!_dir)
return end();
while ((entry = readdir(_dir)))
{
if (strncmp("ttyUSB", entry->d_name, sizeof("ttyUSB") - 1) == 0)
return std::string(entry->d_name);
else if (strncmp("ttyACM", entry->d_name, sizeof("ttyACM") - 1) == 0)
return std::string(entry->d_name);
else if (strncmp("ttyS", entry->d_name, sizeof("ttyS") - 1) == 0)
return std::string(entry->d_name);
}
return end();
}
std::string
LinuxPortFactory::end()
{
return std::string();
}
std::string
LinuxPortFactory::def()
{
return std::string("/dev/ttyACM0");
}

View file

@ -0,0 +1,60 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _LINUXPORTFACTORY_H
#define _LINUXPORTFACTORY_H
class LinuxPortFactory;
#include "PortFactory.h"
#include <sys/types.h>
#include <dirent.h>
#include <string>
class LinuxPortFactory : public PortFactoryBase
{
public:
LinuxPortFactory();
virtual ~LinuxPortFactory();
virtual std::string begin();
virtual std::string end();
virtual std::string next();
virtual std::string def();
virtual SerialPort::Ptr create(const std::string& name);
virtual SerialPort::Ptr create(const std::string& name, bool isUsb);
private:
std::string _empty;
DIR* _dir;
};
#endif // _LINUXPORTFACTORY_H

View file

@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _PORTFACTORY_H
#define _PORTFACTORY_H
#include <string>
#include "SerialPort.h"
class PortFactoryBase
{
public:
PortFactoryBase() {}
virtual ~PortFactoryBase() {}
virtual std::string begin() = 0;
virtual std::string end() = 0;
virtual std::string next() = 0;
virtual std::string def() = 0;
virtual SerialPort::Ptr create(const std::string& name) = 0;
virtual SerialPort::Ptr create(const std::string& name, bool isUsb) = 0;
};
#if defined(__WIN32__)
#include "WinPortFactory.h"
typedef WinPortFactory PortFactory;
#elif defined(__linux__)
#include "LinuxPortFactory.h"
typedef LinuxPortFactory PortFactory;
#elif defined(__APPLE__)
#include "OSXPortFactory.h"
typedef OSXPortFactory PortFactory;
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
// This is likely to work (but not tested) for the other BSDs as well
#include "BSDPortFactory.h"
typedef BSDPortFactory PortFactory;
#else
#error "Platform is not supported"
#endif
#endif // _PORTFACTORY_H

View file

@ -0,0 +1,332 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "PosixSerialPort.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string>
#ifndef B460800
#define B460800 460800
#endif
#ifndef B921600
#define B921600 921600
#endif
PosixSerialPort::PosixSerialPort(const std::string& name, bool isUsb) :
SerialPort(name), _devfd(-1), _isUsb(isUsb), _timeout(0),
_autoFlush(false)
{
}
PosixSerialPort::~PosixSerialPort()
{
if (_devfd >= 0)
::close(_devfd);
}
bool
PosixSerialPort::open(int baud,
int data,
SerialPort::Parity parity,
SerialPort::StopBit stop)
{
struct termios options;
speed_t speed;
// Try opening port assuming _name is full path. If it fails
// try "/dev/" + _name
_devfd = ::open(_name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (_devfd == -1)
{
std::string dev("/dev/");
dev += _name;
_devfd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
if (_devfd == -1)
return false;
}
if (tcgetattr(_devfd, &options) == -1)
{
close();
return false;
}
switch (baud)
{
case 1200:
speed = B1200;
break;
case 9600:
speed = B9600;
break;
case 19200:
speed = B19200;
break;
case 38400:
speed = B38400;
break;
case 57600:
speed = B57600;
break;
case 115200:
speed = B115200;
break;
case 230400:
speed = B230400;
break;
case 460800:
speed = B460800;
break;
case 921600:
speed = B921600;
break;
default:
close();
return false;
}
if (cfsetispeed(&options, speed) || cfsetospeed(&options, speed))
{
close();
return false;
}
options.c_cflag |= (CLOCAL | CREAD);
switch (data)
{
case 8:
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
break;
case 7:
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS7;
break;
default:
close();
return false;
}
switch (parity)
{
case SerialPort::ParityNone:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag &= ~(INPCK | ISTRIP);
break;
case SerialPort::ParityOdd:
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
options.c_iflag |= (INPCK | ISTRIP);
break;
case SerialPort::ParityEven:
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= (INPCK | ISTRIP);
break;
default:
close();
return false;
}
switch (stop)
{
case StopBitOne:
options.c_cflag &= ~CSTOPB;
break;
case StopBitTwo:
options.c_cflag |= CSTOPB;
break;
default:
close();
return false;
}
// No hardware flow control
options.c_cflag &= ~CRTSCTS;
// No software flow control
options.c_iflag &= ~(IXON | IXOFF | IXANY);
// Raw input
options.c_iflag &= ~(BRKINT | ICRNL);
options.c_lflag &= ~(ICANON | IEXTEN | ECHO | ECHOE | ISIG);
// Raw output
options.c_oflag &= ~OPOST;
// No wait time
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 0;
if (tcsetattr(_devfd, TCSANOW, &options))
{
close();
return false;
}
return true;
}
void
PosixSerialPort::close()
{
if (_devfd >= 0)
::close(_devfd);
_devfd = -1;
}
int
PosixSerialPort::read(uint8_t* buffer, int len)
{
fd_set fds;
struct timeval tv;
int numread = 0;
int retval;
if (_devfd == -1)
return -1;
while (numread < len)
{
FD_ZERO(&fds);
FD_SET(_devfd, &fds);
tv.tv_sec = _timeout / 1000;
tv.tv_usec = (_timeout % 1000) * 1000;
retval = select(_devfd + 1, &fds, NULL, NULL, &tv);
if (retval < 0)
{
return -1;
}
else if (retval == 0)
{
return numread;
}
else if (FD_ISSET(_devfd, &fds))
{
retval = ::read(_devfd, (uint8_t*) buffer + numread, len - numread);
if (retval < 0)
return -1;
numread += retval;
}
}
return numread;
}
int
PosixSerialPort::write(const uint8_t* buffer, int len)
{
if (_devfd == -1)
return -1;
int res = ::write(_devfd, buffer, len);
// Used on macos to avoid upload errors
if (_autoFlush)
flush();
return res;
}
int
PosixSerialPort::get()
{
uint8_t byte;
if (_devfd == -1)
return -1;
if (read(&byte, 1) != 1)
return -1;
return byte;
}
int
PosixSerialPort::put(int c)
{
uint8_t byte;
byte = c;
return write(&byte, 1);
}
void
PosixSerialPort::flush()
{
// There isn't a reliable way to flush on a file descriptor
// so we just wait it out. One millisecond is the USB poll
// interval so that should cover it.
usleep(1000);
}
bool
PosixSerialPort::timeout(int millisecs)
{
_timeout = millisecs;
return true;
}
void
PosixSerialPort::setDTR(bool dtr)
{
if (_devfd == -1)
return;
int iFlags = TIOCM_DTR;
ioctl(_devfd, (dtr ? TIOCMBIS : TIOCMBIC), &iFlags);
}
void
PosixSerialPort::setRTS(bool rts)
{
if (_devfd == -1)
return;
int iFlags = TIOCM_RTS;
ioctl(_devfd, (rts ? TIOCMBIS : TIOCMBIC), &iFlags);
}
void
PosixSerialPort::setAutoFlush(bool autoflush)
{
_autoFlush = autoflush;
}

View file

@ -0,0 +1,66 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _POSIXSERIALPORT_H
#define _POSIXSERIALPORT_H
#include "SerialPort.h"
class PosixSerialPort : public SerialPort
{
public:
PosixSerialPort(const std::string& name, bool isUsb);
virtual ~PosixSerialPort();
bool open(int baud = 115200,
int data = 8,
SerialPort::Parity parity = SerialPort::ParityNone,
SerialPort::StopBit stop = SerialPort::StopBitOne);
void close();
bool isUsb() { return _isUsb; };
int read(uint8_t* data, int size);
int write(const uint8_t* data, int size);
int get();
int put(int c);
bool timeout(int millisecs);
void flush();
void setDTR(bool dtr);
void setRTS(bool rts);
void setAutoFlush(bool autoflush);
private:
int _devfd;
bool _isUsb;
int _timeout;
bool _autoFlush;
};
#endif // _POSIXSERIALPORT_H

672
lib/bossac/src/Samba.cpp Normal file
View file

@ -0,0 +1,672 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "Samba.h"
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
using namespace std;
// XMODEM definitions
#define BLK_SIZE 128
#define MAX_RETRIES 5
#define SOH 0x01
#define EOT 0x04
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18
#define START 'C'
#define TIMEOUT_QUICK 100
#define TIMEOUT_NORMAL 1000
#define TIMEOUT_LONG 5000
#define min(a, b) ((a) < (b) ? (a) : (b))
Samba::Samba() :
_canChipErase(false),
_canWriteBuffer(false),
_canChecksumBuffer(false),
_readBufferSize(0),
_debug(false),
_isUsb(false)
{
}
Samba::~Samba()
{
}
bool
Samba::init()
{
uint8_t cmd[3];
_port->timeout(TIMEOUT_QUICK);
// Flush garbage
uint8_t dummy[1024];
_port->read(dummy, sizeof(dummy));
if (!_isUsb)
{
if (_debug)
printf("Send auto-baud\n");
// RS-232 auto-baud sequence
_port->put(0x80);
_port->get();
_port->put(0x80);
_port->get();
_port->put('#');
_port->read(cmd, 3);
}
// Set binary mode
if (_debug)
printf("Set binary mode\n");
cmd[0] = 'N';
cmd[1] = '#';
_port->write(cmd, 2);
_port->read(cmd, 2);
std::string ver;
try
{
ver = version();
}
catch(SambaError& err)
{
return false;
}
std::size_t extIndex = ver.find("[Arduino:");
if (extIndex != string::npos)
{
extIndex += 9;
while (ver[extIndex] != ']')
{
switch (ver[extIndex])
{
case 'X': _canChipErase = true; break;
case 'Y': _canWriteBuffer = true; break;
case 'Z': _canChecksumBuffer = true; break;
}
extIndex++;
}
// All SAMD-based Arduino/AdaFruit boards have a bug in their bootloader
// that trying to read 64 bytes or more over USB corrupts the data.
// We must limit these boards to read chunks of 63 bytes.
if (_isUsb)
_readBufferSize = 63;
}
_port->timeout(TIMEOUT_NORMAL);
return true;
}
bool
Samba::connect(SerialPort::Ptr port, int bps)
{
_port = move(port);
// Try to connect at a high speed if USB
_isUsb = _port->isUsb();
if (_isUsb)
{
if (_port->open(921600) && init())
{
if (_debug)
printf("Connected at 921600 baud\n");
return true;
}
else
{
_port->close();
}
}
_isUsb = false;
// Try the serial port at slower speed
if (_port->open(bps) && init())
{
if (_debug)
printf("Connected at %d baud\n", bps);
return true;
}
disconnect();
return false;
}
void
Samba::disconnect()
{
_port->close();
_port.release();
}
void
Samba::writeByte(uint32_t addr, uint8_t value)
{
uint8_t cmd[14];
if (_debug)
printf("%s(addr=%#x,value=%#x)\n", __FUNCTION__, addr, value);
snprintf((char*) cmd, sizeof(cmd), "O%08X,%02X#", addr, value);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
// The SAM firmware has a bug that if the command and binary data
// are received in the same USB data packet, then the firmware
// gets confused. Even though the writes are separated in the code,
// USB drivers often do write combining which can put them together
// in the same USB data packet. To avoid this, we call the serial
// port object's flush method before writing the data.
if (_isUsb)
_port->flush();
}
uint8_t
Samba::readByte(uint32_t addr)
{
uint8_t cmd[13];
uint8_t value;
snprintf((char*) cmd, sizeof(cmd), "o%08X,4#", addr);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
if (_port->read(cmd, sizeof(uint8_t)) != sizeof(uint8_t))
throw SambaError();
value = cmd[0];
if (_debug)
printf("%s(addr=%#x)=%#x\n", __FUNCTION__, addr, value);
return value;
}
void
Samba::writeWord(uint32_t addr, uint32_t value)
{
uint8_t cmd[20];
if (_debug)
printf("%s(addr=%#x,value=%#x)\n", __FUNCTION__, addr, value);
snprintf((char*) cmd, sizeof(cmd), "W%08X,%08X#", addr, value);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
// The SAM firmware has a bug that if the command and binary data
// are received in the same USB data packet, then the firmware
// gets confused. Even though the writes are sperated in the code,
// USB drivers often do write combining which can put them together
// in the same USB data packet. To avoid this, we call the serial
// port object's flush method before writing the data.
if (_isUsb)
_port->flush();
}
uint32_t
Samba::readWord(uint32_t addr)
{
uint8_t cmd[13];
uint32_t value;
snprintf((char*) cmd, sizeof(cmd), "w%08X,4#", addr);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
if (_port->read(cmd, sizeof(uint32_t)) != sizeof(uint32_t))
throw SambaError();
value = (cmd[3] << 24 | cmd[2] << 16 | cmd[1] << 8 | cmd[0] << 0);
if (_debug)
printf("%s(addr=%#x)=%#x\n", __FUNCTION__, addr, value);
return value;
}
static const uint16_t crc16Table[256] = {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t
Samba::crc16Calc(const uint8_t *data, int len)
{
uint16_t crc16 = 0;
while (len-- > 0)
crc16 = (crc16 << 8) ^ crc16Table[((crc16 >> 8) ^ *(uint8_t*) data++) & 0xff];
return crc16;
}
bool
Samba::crc16Check(const uint8_t *blk)
{
uint16_t crc16;
crc16 = blk[BLK_SIZE + 3] << 8 | blk[BLK_SIZE + 4];
return (crc16Calc(&blk[3], BLK_SIZE) == crc16);
}
void
Samba::crc16Add(uint8_t *blk)
{
uint16_t crc16;
crc16 = crc16Calc(&blk[3], BLK_SIZE);
blk[BLK_SIZE + 3] = (crc16 >> 8) & 0xff;
blk[BLK_SIZE + 4] = crc16 & 0xff;
}
uint16_t
Samba::checksumCalc(uint8_t data, uint16_t crc16) {
return (crc16 << 8) ^ crc16Table[((crc16 >> 8) ^ data) & 0xff];
}
void
Samba::readXmodem(uint8_t* buffer, int size)
{
uint8_t blk[BLK_SIZE + 5];
uint32_t blkNum = 1;
int retries;
int bytes;
while (size > 0)
{
for (retries = 0; retries < MAX_RETRIES; retries++)
{
if (blkNum == 1)
_port->put(START);
bytes = _port->read(blk, sizeof(blk));
if (bytes == sizeof(blk) &&
blk[0] == SOH &&
blk[1] == (blkNum & 0xff) &&
crc16Check(blk))
break;
if (blkNum != 1)
_port->put(NAK);
}
if (retries == MAX_RETRIES)
throw SambaError();
_port->put(ACK);
memmove(buffer, &blk[3], min(size, BLK_SIZE));
buffer += BLK_SIZE;
size -= BLK_SIZE;
blkNum++;
}
for (retries = 0; retries < MAX_RETRIES; retries++)
{
if (_port->get() == EOT)
{
_port->put(ACK);
break;
}
_port->put(NAK);
}
if (retries == MAX_RETRIES)
throw SambaError();
}
void
Samba::writeXmodem(const uint8_t* buffer, int size)
{
uint8_t blk[BLK_SIZE + 5];
uint32_t blkNum = 1;
int retries;
int bytes;
for (retries = 0; retries < MAX_RETRIES; retries++)
{
if (_port->get() == START)
break;
}
if (retries == MAX_RETRIES)
throw SambaError();
while (size > 0)
{
blk[0] = SOH;
blk[1] = (blkNum & 0xff);
blk[2] = ~(blkNum & 0xff);
memmove(&blk[3], buffer, min(size, BLK_SIZE));
if (size < BLK_SIZE)
memset(&blk[3] + size, 0, BLK_SIZE - size);
crc16Add(blk);
for (retries = 0; retries < MAX_RETRIES; retries++)
{
bytes = _port->write(blk, sizeof(blk));
if (bytes != sizeof(blk))
throw SambaError();
if (_port->get() == ACK)
break;
}
if (retries == MAX_RETRIES)
throw SambaError();
buffer += BLK_SIZE;
size -= BLK_SIZE;
blkNum++;
}
for (retries = 0; retries < MAX_RETRIES; retries++)
{
_port->put(EOT);
if (_port->get() == ACK)
break;
}
if (retries == MAX_RETRIES)
throw SambaError();
}
void
Samba::readBinary(uint8_t* buffer, int size)
{
if (_port->read(buffer, size) != size)
throw SambaError();
}
void
Samba::writeBinary(const uint8_t* buffer, int size)
{
while (size)
{
int written = _port->write(buffer, size);
if (written <= 0)
throw SambaError();
buffer += written;
size -= written;
}
}
void
Samba::read(uint32_t addr, uint8_t* buffer, int size)
{
uint8_t cmd[20];
int chunk;
if (_debug)
printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size);
// The SAM firmware has a bug reading powers of 2 over 32 bytes
// via USB. If that is the case here, then read the first byte
// with a readByte and then read one less than the requested size.
if (_isUsb && _readBufferSize == 0 && size > 32 && !(size & (size - 1)))
{
*buffer = readByte(addr);
addr++;
buffer++;
size--;
}
while (size > 0)
{
// Handle any limitations on the size of the read
if (_readBufferSize > 0 && size > _readBufferSize)
chunk = _readBufferSize;
else
chunk = size;
snprintf((char*) cmd, sizeof(cmd), "R%08X,%08X#", addr, chunk);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
if (_isUsb)
readBinary(buffer, chunk);
else
readXmodem(buffer, chunk);
size -= chunk;
addr += chunk;
buffer += chunk;
}
}
void
Samba::write(uint32_t addr, const uint8_t* buffer, int size)
{
uint8_t cmd[20];
if (_debug)
printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size);
snprintf((char*) cmd, sizeof(cmd), "S%08X,%08X#", addr, size);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
// The SAM firmware has a bug that if the command and binary data
// are received in the same USB data packet, then the firmware
// gets confused. Even though the writes are separated in the code,
// USB drivers often do write combining which can put them together
// in the same USB data packet. To avoid this, we call the serial
// port object's flush method before writing the data.
if (_isUsb)
{
_port->flush();
writeBinary(buffer, size);
}
else
{
writeXmodem(buffer, size);
}
}
void
Samba::go(uint32_t addr)
{
uint8_t cmd[11];
if (_debug)
printf("%s(addr=%#x)\n", __FUNCTION__, addr);
snprintf((char*) cmd, sizeof(cmd), "G%08X#", addr);
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
throw SambaError();
// The SAM firmware can get confused if another command is
// received in the same USB data packet as the go command
// so we flush after writing the command over USB.
if (_isUsb)
_port->flush();
}
std::string
Samba::version()
{
uint8_t cmd[256];
char* str;
int size;
int pos;
cmd[0] = 'V';
cmd[1] = '#';
_port->write(cmd, 2);
_port->timeout(TIMEOUT_QUICK);
size = _port->read(cmd, sizeof(cmd) - 1);
_port->timeout(TIMEOUT_NORMAL);
if (size <= 0)
throw SambaError();
str = (char*) cmd;
for (pos = 0; pos < size; pos++)
{
if (!isprint(str[pos]))
break;
}
str[pos] = '\0';
std::string ver(str);
if (_debug)
printf("%s()=%s\n", __FUNCTION__, ver.c_str());
return ver;
}
void
Samba::chipErase(uint32_t start_addr)
{
if (!_canChipErase)
throw SambaError();
uint8_t cmd[64];
if (_debug)
printf("%s(addr=%#x)\n", __FUNCTION__, start_addr);
int l = snprintf((char*) cmd, sizeof(cmd), "X%08X#", start_addr);
if (_port->write(cmd, l) != l)
throw SambaError();
_port->timeout(TIMEOUT_LONG);
_port->read(cmd, 3); // Expects "X\n\r"
_port->timeout(TIMEOUT_NORMAL);
if (cmd[0] != 'X')
throw SambaError();
}
void
Samba::writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size)
{
if (!_canWriteBuffer)
throw SambaError();
if (size > checksumBufferSize())
throw SambaError();
if (_debug)
printf("%s(scr_addr=%#x, dst_addr=%#x, size=%#x)\n", __FUNCTION__, src_addr, dst_addr, size);
uint8_t cmd[64];
int l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,0#", src_addr);
if (_port->write(cmd, l) != l)
throw SambaError();
_port->timeout(TIMEOUT_QUICK);
cmd[0] = 0;
_port->read(cmd, 3); // Expects "Y\n\r"
_port->timeout(TIMEOUT_NORMAL);
if (cmd[0] != 'Y')
throw SambaError();
l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,%08X#", dst_addr, size);
if (_port->write(cmd, l) != l)
throw SambaError();
_port->timeout(TIMEOUT_LONG);
cmd[0] = 0;
_port->read(cmd, 3); // Expects "Y\n\r"
_port->timeout(TIMEOUT_NORMAL);
if (cmd[0] != 'Y')
throw SambaError();
}
uint16_t
Samba::checksumBuffer(uint32_t start_addr, uint32_t size)
{
if (!_canChecksumBuffer)
throw SambaError();
if (size > checksumBufferSize())
throw SambaError();
if (_debug)
printf("%s(start_addr=%#x, size=%#x) = ", __FUNCTION__, start_addr, size);
uint8_t cmd[64];
int l = snprintf((char*) cmd, sizeof(cmd), "Z%08X,%08X#", start_addr, size);
if (_port->write(cmd, l) != l)
throw SambaError();
_port->timeout(TIMEOUT_LONG);
cmd[0] = 0;
_port->read(cmd, 12); // Expects "Z00000000#\n\r"
_port->timeout(TIMEOUT_NORMAL);
if (cmd[0] != 'Z')
throw SambaError();
cmd[9] = 0;
errno = 0;
uint32_t res = strtol((char*) &cmd[1], NULL, 16);
if (errno != 0)
throw SambaError();
if (_debug)
printf("%x\n", res);
return res;
}

115
lib/bossac/src/Samba.h Normal file
View file

@ -0,0 +1,115 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _SAMBA_H
#define _SAMBA_H
#include <string>
#include <stdint.h>
#include <exception>
#include <memory>
#include "SerialPort.h"
class SambaError : public std::exception
{
public:
SambaError() : exception() {};
const char* what() const throw() { return "SAM-BA operation failed"; }
};
class Samba
{
public:
Samba();
virtual ~Samba();
bool connect(SerialPort::Ptr port, int bps = 115200);
void disconnect();
void writeByte(uint32_t addr, uint8_t value);
uint8_t readByte(uint32_t addr);
void writeWord(uint32_t addr, uint32_t value);
uint32_t readWord(uint32_t addr);
void write(uint32_t addr, const uint8_t* buffer, int size);
void read(uint32_t addr, uint8_t* buffer, int size);
void go(uint32_t addr);
std::string version();
void chipId(uint32_t& chipId, uint32_t& extChipId);
void setDebug(bool debug) { _debug = debug; }
const SerialPort& getSerialPort() { return *_port; }
void reset();
// Extended SAM-BA functions
bool canChipErase() { return _canChipErase; }
void chipErase(uint32_t start_addr);
bool canWriteBuffer() { return _canWriteBuffer; }
void writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size);
uint32_t writeBufferSize() { return 4096; }
bool canChecksumBuffer() { return _canChecksumBuffer; }
uint16_t checksumBuffer(uint32_t start_addr, uint32_t size);
uint32_t checksumBufferSize() { return 4096; }
uint16_t checksumCalc(uint8_t c, uint16_t crc);
private:
bool _canChipErase;
bool _canWriteBuffer;
bool _canChecksumBuffer;
int _readBufferSize;
bool _debug;
bool _isUsb;
SerialPort::Ptr _port;
bool init();
uint16_t crc16Calc(const uint8_t *data, int len);
bool crc16Check(const uint8_t *blk);
void crc16Add(uint8_t *blk);
void writeXmodem(const uint8_t* buffer, int size);
void readXmodem(uint8_t* buffer, int size);
void writeBinary(const uint8_t* buffer, int size);
void readBinary(uint8_t* buffer, int size);
};
#endif // _SAMBA_H

View file

@ -0,0 +1,82 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _SERIALPORT_H
#define _SERIALPORT_H
#include <string>
#include <memory>
#include <stdint.h>
class SerialPort
{
public:
SerialPort(const std::string& name) : _name(name) {}
virtual ~SerialPort() {}
enum Parity
{
ParityNone,
ParityOdd,
ParityEven,
};
enum StopBit
{
StopBitOne,
StopBitOneFive,
StopBitTwo,
};
virtual bool open(int baud = 115200,
int data = 8,
Parity parity = ParityNone,
StopBit stop = StopBitOne) = 0;
virtual void close() = 0;
virtual bool isUsb() = 0;
virtual int read(uint8_t* data, int size) = 0;
virtual int write(const uint8_t* data, int size) = 0;
virtual int get() = 0;
virtual int put(int c) = 0;
virtual bool timeout(int millisecs) = 0;
virtual void flush() = 0;
virtual void setDTR(bool dtr) = 0;
virtual void setRTS(bool rts) = 0;
virtual std::string name() const { return _name; }
typedef std::unique_ptr<SerialPort> Ptr;
protected:
std::string _name;
};
#endif // _SERIALPORT_H

View file

@ -0,0 +1,62 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include "WordCopyApplet.h"
WordCopyApplet::WordCopyApplet(Samba& samba, uint32_t addr)
: Applet(samba,
addr,
applet.code,
sizeof(applet.code),
addr + applet.start,
addr + applet.stack,
addr + applet.reset)
{
}
WordCopyApplet::~WordCopyApplet()
{
}
void
WordCopyApplet::setDstAddr(uint32_t dstAddr)
{
_samba.writeWord(_addr + applet.dst_addr, dstAddr);
}
void
WordCopyApplet::setSrcAddr(uint32_t srcAddr)
{
_samba.writeWord(_addr + applet.src_addr, srcAddr);
}
void
WordCopyApplet::setWords(uint32_t words)
{
_samba.writeWord(_addr + applet.words, words);
}

View file

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#ifndef _WORDCOPYAPPLET_H
#define _WORDCOPYAPPLET_H
#include "Applet.h"
#include "WordCopyArm.h"
class WordCopyApplet : public Applet
{
public:
WordCopyApplet(Samba& samba, uint32_t addr);
virtual ~WordCopyApplet();
void setDstAddr(uint32_t dstAddr);
void setSrcAddr(uint32_t srcAddr);
void setWords(uint32_t words);
private:
static WordCopyArm applet;
};
#endif // _WORDCOPYAPPLET_H

View file

@ -0,0 +1,47 @@
.global start
.global stack
.global reset
.global dst_addr
.global src_addr
.global words
.text
.thumb
.align 0
start:
ldr r0, dst_addr
ldr r1, src_addr
ldr r2, words
b check
copy:
ldmia r1!, {r3}
stmia r0!, {r3}
sub r2, #1
check:
cmp r2, #0
bne copy
@ Fix for SAM-BA stack bug
ldr r0, reset
cmp r0, #0
bne return
ldr r0, stack
mov sp, r0
return:
bx lr
.align 0
stack:
.word 0
reset:
.word 0
dst_addr:
.word 0
src_addr:
.word 0
words:
.word 0

View file

@ -0,0 +1,25 @@
// WARNING!!! DO NOT EDIT - FILE GENERATED BY APPLETGEN
#include "WordCopyArm.h"
#include "WordCopyApplet.h"
WordCopyArm WordCopyApplet::applet = {
// dst_addr
0x00000028,
// reset
0x00000024,
// src_addr
0x0000002c,
// stack
0x00000020,
// start
0x00000000,
// words
0x00000030,
// code
{
0x09, 0x48, 0x0a, 0x49, 0x0a, 0x4a, 0x02, 0xe0, 0x08, 0xc9, 0x08, 0xc0, 0x01, 0x3a, 0x00, 0x2a,
0xfa, 0xd1, 0x04, 0x48, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x48, 0x85, 0x46, 0x70, 0x47, 0xc0, 0x46,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}
};

View file

@ -0,0 +1,18 @@
// WARNING!!! DO NOT EDIT - FILE GENERATED BY APPLETGEN
#ifndef _WORDCOPYARM_H
#define _WORDCOPYARM_H
#include <stdint.h>
typedef struct
{
uint32_t dst_addr;
uint32_t reset;
uint32_t src_addr;
uint32_t stack;
uint32_t start;
uint32_t words;
uint8_t code[52];
} WordCopyArm;
#endif // _WORDCOPYARM_H

489
lib/bossac/src/bossac.cpp Normal file
View file

@ -0,0 +1,489 @@
///////////////////////////////////////////////////////////////////////////////
// BOSSA
//
// Copyright (c) 2011-2018, ShumaTech
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///////////////////////////////////////////////////////////////////////////////
#include <string>
#include <exception>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/time.h>
#include "CmdOpts.h"
#include "Samba.h"
#include "PortFactory.h"
#include "Device.h"
#include "Flasher.h"
using namespace std;
class BossaConfig
{
public:
BossaConfig();
virtual ~BossaConfig() {}
bool erase;
bool write;
bool read;
bool verify;
bool offset;
bool reset;
bool port;
bool boot;
bool bor;
bool bod;
bool lock;
bool unlock;
bool security;
bool info;
bool debug;
bool help;
bool usbPort;
bool arduinoErase;
int readArg;
int offsetArg;
string portArg;
int bootArg;
int bodArg;
int borArg;
string lockArg;
string unlockArg;
bool usbPortArg;
};
BossaConfig::BossaConfig()
{
erase = false;
write = false;
read = false;
verify = false;
port = false;
boot = false;
bod = false;
bor = false;
lock = false;
security = false;
info = false;
help = false;
usbPort = false;
arduinoErase = false;
readArg = 0;
offsetArg = 0;
bootArg = 1;
bodArg = 1;
borArg = 1;
usbPortArg=1;
reset = false;
}
class BossaObserver : public FlasherObserver
{
public:
BossaObserver() : _lastTicks(-1) {}
virtual ~BossaObserver() {}
virtual void onStatus(const char *message, ...);
virtual void onProgress(int num, int div);
private:
int _lastTicks;
};
void
BossaObserver::onStatus(const char *message, ...)
{
va_list ap;
va_start(ap, message);
vprintf(message, ap);
va_end(ap);
}
void
BossaObserver::onProgress(int num, int div)
{
int ticks;
int bars = 30;
ticks = num * bars / div;
if (ticks == _lastTicks)
return;
printf("\r[");
while (ticks-- > 0)
{
putchar('=');
bars--;
}
while (bars-- > 0)
{
putchar(' ');
}
printf("] %d%% (%d/%d pages)", num * 100 / div, num, div);
fflush(stdout);
_lastTicks = 0;
}
static BossaConfig config;
static Option opts[] =
{
{
'e', "erase", &config.erase,
{ ArgNone },
"erase the entire flash starting at the offset"
},
{
'w', "write", &config.write,
{ ArgNone },
"write FILE to the flash; accelerated when\n"
"combined with erase option"
},
{
'r', "read", &config.read,
{ ArgOptional, ArgInt, "SIZE", { &config.readArg } },
"read SIZE from flash and store in FILE;\n"
"read entire flash if SIZE not specified"
},
{
'v', "verify", &config.verify,
{ ArgNone },
"verify FILE matches flash contents"
},
{
'o', "offset", &config.offset,
{ ArgRequired, ArgInt, "OFFSET", { &config.offsetArg } },
"start erase/write/read/verify operation at flash OFFSET;\n"
"OFFSET must be aligned to a flash page boundary"
},
{
'p', "port", &config.port,
{ ArgRequired, ArgString, "PORT", { &config.portArg } },
"use serial PORT to communicate to device;\n"
"default behavior is to use first serial port"
},
{
'b', "boot", &config.boot,
{ ArgOptional, ArgInt, "BOOL", { &config.bootArg } },
"boot from ROM if BOOL is 0;\n"
"boot from FLASH if BOOL is 1 [default];\n"
"option is ignored on unsupported devices"
},
{
'c', "bod", &config.bod,
{ ArgOptional, ArgInt, "BOOL", { &config.bodArg } },
"no brownout detection if BOOL is 0;\n"
"brownout detection is on if BOOL is 1 [default]"
},
{
't', "bor", &config.bor,
{ ArgOptional, ArgInt, "BOOL", { &config.borArg } },
"no brownout reset if BOOL is 0;\n"
"brownout reset is on if BOOL is 1 [default]"
},
{
'l', "lock", &config.lock,
{ ArgOptional, ArgString, "REGION", { &config.lockArg } },
"lock the flash REGION as a comma-separated list;\n"
"lock all if not given [default]"
},
{
'u', "unlock", &config.unlock,
{ ArgOptional, ArgString, "REGION", { &config.unlockArg } },
"unlock the flash REGION as a comma-separated list;\n"
"unlock all if not given [default]"
},
{
's', "security", &config.security,
{ ArgNone },
"set the flash security flag"
},
{
'i', "info", &config.info,
{ ArgNone },
"display device information"
},
{
'd', "debug", &config.debug,
{ ArgNone },
"print debug messages"
},
{
'h', "help", &config.help,
{ ArgNone },
"display this help text"
},
{
'U', "usb-port", &config.usbPort,
{ ArgOptional, ArgInt, "BOOL", { &config.usbPortArg } },
"force serial port detection to USB if BOOL is 1 [default]\n"
"or to RS-232 if BOOL is 0"
},
{
'R', "reset", &config.reset,
{ ArgNone },
"reset CPU (if supported)"
},
{
'a', "arduino-erase", &config.arduinoErase,
{ ArgNone },
"erase and reset via Arduino 1200 baud hack"
}
};
int
help(const char* program)
{
fprintf(stderr, "Try '%s -h' or '%s --help' for more information\n", program, program);
return 1;
}
static struct timeval start_time;
void
timer_start()
{
gettimeofday(&start_time, NULL);
}
float
timer_stop()
{
struct timeval end;
gettimeofday(&end, NULL);
return (end.tv_sec - start_time.tv_sec) + (end.tv_usec - start_time.tv_usec) / 1000000.0;
}
int
main(int argc, char* argv[])
{
int args;
char* pos;
CmdOpts cmd(argc, argv, sizeof(opts) / sizeof(opts[0]), opts);
if ((pos = strrchr(argv[0], '/')) || (pos = strrchr(argv[0], '\\')))
argv[0] = pos + 1;
if (argc <= 1)
{
fprintf(stderr, "%s: you must specify at least one option\n", argv[0]);
return help(argv[0]);
}
args = cmd.parse();
if (args < 0)
return help(argv[0]);
if (config.read && (config.write || config.verify))
{
fprintf(stderr, "%s: read option is exclusive of write or verify\n", argv[0]);
return help(argv[0]);
}
if (config.read || config.write || config.verify)
{
if (args == argc)
{
fprintf(stderr, "%s: missing file\n", argv[0]);
return help(argv[0]);
}
argc--;
}
if (args != argc)
{
fprintf(stderr, "%s: extra arguments found\n", argv[0]);
return help(argv[0]);
}
if (config.help)
{
printf("Usage: %s [OPTION...] [FILE]\n", argv[0]);
printf("Basic Open Source SAM-BA Application (BOSSA) Version " VERSION "\n"
"Flash programmer for Atmel SAM devices.\n"
"Copyright (c) 2011-2018 ShumaTech (http://www.shumatech.com)\n"
"\n"
"Examples:\n"
" bossac -e -w -v -b image.bin # Erase flash, write flash with image.bin,\n"
" # verify the write, and set boot from flash\n"
" bossac -r0x10000 image.bin # Read 64KB from flash and store in image.bin\n"
);
printf("\nOptions:\n");
cmd.usage(stdout);
printf("\nReport bugs to <bugs@shumatech.com>\n");
return 1;
}
try
{
Samba samba;
PortFactory portFactory;
if (config.debug)
samba.setDebug(true);
if (!config.port)
config.portArg = portFactory.def();
if (config.arduinoErase)
{
SerialPort::Ptr port;
port = portFactory.create(config.portArg, config.usbPortArg != 0);
if(!port->open(1200))
{
fprintf(stderr, "Failed to open port at 1200bps\n");
return 1;
}
port->setRTS(true);
port->setDTR(false);
port->close();
}
if (config.portArg.empty())
{
fprintf(stderr, "No serial ports available\n");
return 1;
}
bool res;
if (config.usbPort)
res = samba.connect(portFactory.create(config.portArg, config.usbPortArg != 0));
else
res = samba.connect(portFactory.create(config.portArg));
if (!res)
{
fprintf(stderr, "No device found on %s\n", config.portArg.c_str());
return 1;
}
Device device(samba);
device.create();
Device::FlashPtr& flash = device.getFlash();
BossaObserver observer;
Flasher flasher(samba, device, observer);
if (config.info)
{
FlasherInfo info;
flasher.info(info);
info.print();
}
if (config.unlock)
flasher.lock(config.unlockArg, false);
if (config.erase)
{
timer_start();
flasher.erase(config.offsetArg);
printf("\nDone in %5.3f seconds\n", timer_stop());
}
if (config.write)
{
timer_start();
flasher.write(argv[args], config.offsetArg);
printf("\nDone in %5.3f seconds\n", timer_stop());
}
if (config.verify)
{
uint32_t pageErrors;
uint32_t totalErrors;
timer_start();
if (!flasher.verify(argv[args], pageErrors, totalErrors, config.offsetArg))
{
printf("\nVerify failed\nPage errors: %d\nByte errors: %d\n",
pageErrors, totalErrors);
return 2;
}
printf("\nVerify successful\nDone in %5.3f seconds\n", timer_stop());
}
if (config.read)
{
timer_start();
flasher.read(argv[args], config.readArg, config.offsetArg);
printf("\nDone in %5.3f seconds\n", timer_stop());
}
if (config.boot)
{
printf("Set boot flash %s\n", config.bootArg ? "true" : "false");
flash->setBootFlash(config.bootArg);
}
if (config.bod)
{
printf("Set brownout detect %s\n", config.bodArg ? "true" : "false");
flash->setBod(config.bodArg);
}
if (config.bor)
{
printf("Set brownout reset %s\n", config.borArg ? "true" : "false");
flash->setBor(config.borArg);
}
if (config.security)
{
printf("Set security\n");
flash->setSecurity();
}
if (config.lock)
flasher.lock(config.lockArg, true);
flash->writeOptions();
if (config.reset)
device.reset();
}
catch (exception& e)
{
fprintf(stderr, "\n%s\n", e.what());
return 1;
}
catch(...)
{
fprintf(stderr, "\nUnhandled exception\n");
return 1;
}
return 0;
}