Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
Signed-off-by: Loic Lefort <[email protected]>
  • Loading branch information
loiclefort committed May 9, 2016
0 parents commit ce83076
Show file tree
Hide file tree
Showing 13 changed files with 1,524 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
GPATH
GRTAGS
GTAGS
*.o
*~
339 changes: 339 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CFLAGS=-std=gnu99 -Wall

BINARY=usamba
SOURCES = usamba.c comm.c chipid.c eefc.c
OBJS = $(SOURCES:.c=.o)

$(BINARY): $(OBJS)

clean:
@rm -f $(OBJS) $(BINARY)
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Micro SAM-BA
------------

# Description

This simple tool can be used to program the internal flash of the following
microcontrollers:

- Atmel SAME70/S70/V70/V71

Communication with SAM-BA bootloader is only supported through USB.

Before using the tool, the MCU must be put in "Boot from ROM" mode, either by
fully erasing it using the ERASE pin or by clearing GPVNM1 (see datasheet for
more information). When the device is in this mode, it will be enumerated as:

03eb:6124 Atmel Corp. at91sam SAMBA bootloader

# Usage

Usage: ``./usamba <port> (read|write|verify|erase-all|gpnvm) [args]*``

- Read Flash:
``./usamba <port> read <filename> <start-address> <size>``

- Write Flash:
``./usamba <port> write <filename> <start-address>``

- Verify Flash:
``./usamba <port> verify <filename> <start-address>``

- Erase Flash:
``./usamba <port> erase-all``

- Get/Set/Clear GPNVM:
``./usamba <port> gpnvm (get|set|clear) <gpnvm_number>``

for all commands:
``<port>`` is the USB device node for the SAM-BA bootloader, for
example ``/dev/ttyACM0``.
``<start-address>`` and ``<size>`` can be specified in decimal, hexadecimal (if
prefixed by ``0x``) or octal (if prefixed by ``0``).
99 changes: 99 additions & 0 deletions chipid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2015-2016, Atmel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/

#include <string.h>
#include "chipid.h"
#include "comm.h"
#include "utils.h"

static const struct _chip _chips_samx7[] = {
{ "SAME70Q21", 0xa1020e00, 0x00000002, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAME70Q20", 0xa1020c00, 0x00000002, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAME70Q19", 0xa10d0a00, 0x00000002, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAME70N21", 0xa1020e00, 0x00000001, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAME70N20", 0xa1020c00, 0x00000001, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAME70N19", 0xa10d0a00, 0x00000001, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAME70J21", 0xa1020e00, 0x00000000, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAME70J20", 0xa1020c00, 0x00000000, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAME70J19", 0xa10d0a00, 0x00000000, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMS70Q21", 0xa1120e00, 0x00000002, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAMS70Q20", 0xa1120c00, 0x00000002, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMS70Q19", 0xa11d0a00, 0x00000002, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMS70N21", 0xa1120e00, 0x00000001, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAMS70N20", 0xa1120c00, 0x00000001, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMS70N19", 0xa11d0a00, 0x00000001, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMS70J21", 0xa1120e00, 0x00000000, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAMS70J20", 0xa1120c00, 0x00000000, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMS70J19", 0xa11d0a00, 0x00000000, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMV71Q21", 0xa1220e00, 0x00000002, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAMV71Q20", 0xa1220c00, 0x00000002, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMV71Q19", 0xa12d0a00, 0x00000002, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMV71N21", 0xa1220e00, 0x00000001, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAMV71N20", 0xa1220c00, 0x00000001, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMV71N19", 0xa12d0a00, 0x00000001, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMV71J21", 0xa1220e00, 0x00000000, 0x400e0c00, 0x00400000, 2048, 9 },
{ "SAMV71J20", 0xa1220c00, 0x00000000, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMV71J19", 0xa12d0a00, 0x00000000, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMV70Q20", 0xa1320c00, 0x00000002, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMV70Q19", 0xa13d0a00, 0x00000002, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMV70N20", 0xa1320c00, 0x00000001, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMV70N19", 0xa13d0a00, 0x00000001, 0x400e0c00, 0x00400000, 512, 9 },
{ "SAMV70J20", 0xa1320c00, 0x00000000, 0x400e0c00, 0x00400000, 1024, 9 },
{ "SAMV70J19", 0xa13d0a00, 0x00000000, 0x400e0c00, 0x00400000, 512, 9 },
};

static const struct _chip_serie _chip_series[] = {
{
.name = "samx7",
.cidr_reg = 0x400e0940,
.exid_reg = 0x400e0944,
.nb_chips = ARRAY_SIZE(_chips_samx7),
.chips = _chips_samx7,
},
};

const struct _chip_serie* chipid_get_serie(const char* name)
{
for (int i = 0; i < ARRAY_SIZE(_chip_series); i++)
if (!strcmp(_chip_series[i].name, name))
return &_chip_series[i];
return NULL;
}

bool chipid_check_serie(int fd, const struct _chip_serie* serie, const struct _chip** chip)
{
// Read chip identifiers (CIDR/EXID)
uint32_t cidr, exid;
if (!samba_read_word(fd, serie->cidr_reg, &cidr))
return false;
if (!samba_read_word(fd, serie->exid_reg, &exid))
return false;

// Identify chip and read its flash infos
for (int i = 0; i < serie->nb_chips; i++) {
if (serie->chips[i].cidr == cidr && serie->chips[i].exid == exid) {
*chip = &serie->chips[i];
return true;
}
}

return false;
}

const struct _chip_serie* chipid_identity_serie(int fd, const struct _chip** chip)
{
for (int i = 0; i < ARRAY_SIZE(_chip_series); i++)
if (chipid_check_serie(fd, &_chip_series[i], chip))
return &_chip_series[i];
return NULL;
}
44 changes: 44 additions & 0 deletions chipid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2015-2016, Atmel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/

#ifndef CHIPID_H_
#define CHIPID_H_

#include <stdbool.h>
#include <stdint.h>

struct _chip {
const char* name;
uint32_t cidr;
uint32_t exid;
uint32_t eefc_base;
uint32_t flash_addr;
uint32_t flash_size;
uint8_t gpnvm;
};

struct _chip_serie {
const char* name;
uint32_t cidr_reg;
uint32_t exid_reg;
uint32_t nb_chips;
const struct _chip* chips;
};

extern const struct _chip_serie* chipid_get_serie(const char* name);

extern bool chipid_check_serie(int fd, const struct _chip_serie* serie, const struct _chip** chip);

extern const struct _chip_serie* chipid_identity_serie(int fd, const struct _chip** chip);

#endif /* CHIPID_H_ */
144 changes: 144 additions & 0 deletions comm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright (c) 2015-2016, Atmel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "comm.h"
#include "utils.h"

static bool configure_tty(int fd, int speed)
{
struct termios tty;

memset(&tty, 0, sizeof(tty));

if (tcgetattr(fd, &tty) != 0) {
perror("error from tcgetattr: ");
return false;
}

if (speed) {
cfsetospeed(&tty, speed);
cfsetispeed(&tty, speed);
}

tty.c_cflag &= ~(CSIZE | PARENB | PARODD | CSTOPB | CRTSCTS);
tty.c_cflag |= CS8 | CLOCAL | CREAD;
tty.c_lflag = 0;
tty.c_oflag = 0;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 5;
tty.c_iflag &= ~(ICRNL | IGNBRK | IXON | IXOFF | IXANY);

if (tcsetattr(fd, TCSANOW, &tty) != 0) {
perror("error from tcsetattr: ");
return false;
}

return true;
}

static bool switch_to_binary(int fd)
{
char cmd[] = "N#";
if (write(fd, cmd, strlen(cmd)) != strlen(cmd))
return false;
return read(fd, cmd, 2) == 2;
}

int samba_open(const char* device)
{
int fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
perror("Could not open device");
return -1;
}

if (!configure_tty(fd, B4000000)) {
close(fd);
return -1;
}

if (!switch_to_binary(fd)) {
close(fd);
return -1;
}

return fd;
}

void samba_close(int fd)
{
close(fd);
}

bool samba_read_word(int fd, uint32_t addr, uint32_t* value)
{
char cmd[12];
snprintf(cmd, sizeof(cmd), "w%08x,#", addr);
if (write(fd, cmd, strlen(cmd)) != strlen(cmd))
return false;
return read(fd, value, 4) == 4;
}

bool samba_write_word(int fd, uint32_t addr, uint32_t value)
{
char cmd[20];
snprintf(cmd, sizeof(cmd), "W%08x,%08x#", addr, value);
return write(fd, cmd, strlen(cmd)) == strlen(cmd);
}

bool samba_read(int fd, uint8_t* buffer, uint32_t addr, uint32_t size)
{
char cmd[20];
while (size > 0) {
uint32_t count = MIN(size, 1024);
// workaround for bug when size is exactly 512
if (count == 512)
count = 1;
snprintf(cmd, sizeof(cmd), "R%08x,%08x#", addr, count);
if (write(fd, cmd, strlen(cmd)) != strlen(cmd))
return false;
if (read(fd, buffer, count) != count)
return false;
addr += count;
buffer += count;
size -= count;
}
return true;
}

bool samba_write(int fd, uint8_t* buffer, uint32_t addr, uint32_t size)
{
char cmd[20];
while (size > 0) {
uint32_t count = MIN(size, 1024);
// workaround for bug when size is exactly 512
if (count == 512)
count = 1;
snprintf(cmd, sizeof(cmd), "S%08x,%08x#", addr, count);
if (write(fd, cmd, strlen(cmd)) != strlen(cmd))
return false;
if (write(fd, buffer, count) != count)
return false;
buffer += count;
size -= count;
}
return true;
}
32 changes: 32 additions & 0 deletions comm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2015-2016, Atmel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*/

#ifndef COMM_H_
#define COMM_H_

#include <stdbool.h>
#include <stdint.h>

extern int samba_open(const char* device);

extern void samba_close(int fd);

extern bool samba_read_word(int fd, uint32_t addr, uint32_t* value);

extern bool samba_write_word(int fd, uint32_t addr, uint32_t value);

extern bool samba_read(int fd, uint8_t* buffer, uint32_t addr, uint32_t size);

extern bool samba_write(int fd, uint8_t* buffer, uint32_t addr, uint32_t size);

#endif /* COMM_H_ */
Loading

0 comments on commit ce83076

Please sign in to comment.