working version

This commit is contained in:
Olaf Rempel 2008-03-03 22:32:38 +01:00
parent fded24a803
commit bd59d4924f
5 changed files with 155 additions and 34 deletions

View File

@ -18,6 +18,7 @@
***************************************************************************/
#include <stdint.h>
#include "AT91SAM7S256.h"
#include "board.h"
static void empty_isr(void) {}
@ -36,7 +37,7 @@ void at91_init1(void)
*AT91C_RSTC_RMR = (AT91C_RSTC_KEY & 0xA5 << 24) | AT91C_RSTC_URSTEN;
/* Set Flash Waitstates */
*AT91C_MC_FMR = AT91C_MC_FWS_1FWS;
*AT91C_MC_FMR = (AT91C_MC_FMCN & ((MCK / 666666) << 16)) | AT91C_MC_FWS_1FWS;
/*
* Enable main oscillator (MAINCK)

View File

@ -1,7 +1,7 @@
#ifndef AT91TWI_H_
#define AT91TWI_H_
#include <list.h>
#include <stdint.h>
/* TWI slave addresses */
#define TWI_ADDR_BL1 0x21
@ -10,7 +10,7 @@
#define TWI_ADDR_BL4 0x24
#define TWI_ADDR_EEPROM 0x40
/* TWIBOOT commands */
/* TWIBOOT commands */
#define CMD_WAIT 0x00
#define CMD_GET_INFO 0x10
#define CMD_GET_SIGNATURE 0x11
@ -33,7 +33,7 @@
struct blmc_cmd {
uint32_t cmd; /* cmd byte(s) */
uint8_t mode; /* read/write, cmdlen (1-3 bytes) */
uint8_t size; /* data size */
uint16_t size; /* data size */
uint8_t *data; /* read/write data */
};

View File

@ -210,8 +210,8 @@ void at91_twi_test(void)
cmd.cmd = CMD_GET_SIGNATURE;
cmd.size = 4;
ret = twi_cmd(i, &cmd);
printf("sig(%ld):0x%02x%02x%02x ", ret, buf[0], buf[1], buf[2]);
printf("sig(%ld):0x%02x%02x%02x\n\r", ret, buf[0], buf[1], buf[2]);
/*
cmd.cmd = CMD_BOOT_APPLICATION;
cmd.mode = BLMC_CMD_WRITE | BLMC_CMD_0_ARG;
cmd.size = 0;
@ -225,6 +225,7 @@ void at91_twi_test(void)
cmd.data = buf,
ret = twi_cmd(i, &cmd);
printf("app(%ld):'%s'\n\r", ret, buf);
*/
}
}

View File

@ -182,13 +182,12 @@ static const struct usb_string_descriptor usb_string1 = {
};
static const struct usb_string_descriptor usb_string2 = {
/* String 2 "device firmware upgrade" */
.bLength = sizeof(struct usb_string_descriptor) + 23 * sizeof(uint16_t),
/* String 2 "sam7fc-dfu" */
.bLength = sizeof(struct usb_string_descriptor) + 10 * sizeof(uint16_t),
.bDescriptorType = USB_DT_STRING,
.wData = {
0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0066,
0x0069, 0x0072, 0x006d, 0x0077, 0x0061, 0x0072, 0x0065, 0x0020,
0x0075, 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065,
0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063, 0x002d, 0x0064,
0x0066, 0x0075,
},
};
@ -262,7 +261,7 @@ void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
void (*complete_cb)(void))
{
struct ep_ctx *ctx = &ep_ctx[ep];
// printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
// printf("ep_transfer_send(%ld) size=%ld(%d) flags=0x%x\n\r", ep, length, ctx->maxpktsize, ctx->flags);
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
return;
@ -448,6 +447,10 @@ static void udp_handle_ep(uint32_t ep)
if (!(*csr & AT91C_UDP_EPEDS))
return;
/* clear STALLSENT interrupt */
if (*csr & AT91C_UDP_STALLSENT)
csr_clear_flags(*csr, (AT91C_UDP_STALLSENT | AT91C_UDP_FORCESTALL));
/* ctrl request packet? */
if (*csr & AT91C_UDP_RXSETUP) {
struct usb_ctrlrequest req;
@ -455,6 +458,10 @@ static void udp_handle_ep(uint32_t ep)
for (p = (uint8_t *)&req; p < (uint8_t *)(&req +1); p++)
*p = AT91C_UDP_FDR[ep];
/* ack bank0 *now */
if (*csr & AT91C_UDP_RX_DATA_BK0)
csr_clear_flags(*csr, AT91C_UDP_RX_DATA_BK0);
/* set data phase transfer direction */
if (req.bRequestType & USB_DIR_IN)
*csr |= AT91C_UDP_DIR;
@ -500,10 +507,6 @@ static void udp_handle_ep(uint32_t ep)
*csr &= ~(AT91C_UDP_TXCOMP);
}
/* clear STALLSENT interrupt */
if (*csr & AT91C_UDP_STALLSENT)
csr_clear_flags(*csr, (AT91C_UDP_STALLSENT | AT91C_UDP_FORCESTALL));
/* data ready to read? */
if (*csr & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
struct ep_ctx *ctx = &ep_ctx[ep];
@ -517,6 +520,8 @@ static void udp_handle_ep(uint32_t ep)
ctx->transfer->curpos = 0;
}
void *exec_cb = NULL;
if (ctx->flags & CTX_FIFO) {
fifo_rxudp(ctx->fifo, ep, len);
@ -534,8 +539,8 @@ static void udp_handle_ep(uint32_t ep)
if (transfer->length == transfer->curpos) {
ctx->flags &= ~CTX_OUT;
if (transfer->complete_cb)
transfer->complete_cb();
/* exec callback after rxbank ack */
exec_cb = transfer->complete_cb;
}
}
@ -553,6 +558,9 @@ static void udp_handle_ep(uint32_t ep)
ctx->flags = (ctx->flags & ~CTX_RXBANK1) | CTX_RXBANK0;
}
if (exec_cb)
ctx->transfer->complete_cb();
}
}

143
src/dfu.c
View File

@ -20,6 +20,7 @@
#include "AT91SAM7S256.h"
#include "board.h"
#include "at91_twi.h"
#include "at91_udp.h"
#include "usb_ch9.h"
@ -36,7 +37,7 @@ static void handle_getstatus(void)
{
struct dfu_status dstat;
uint32_t fmr = *AT91C_MC_FMR;
uint32_t fmr = *AT91C_MC_FSR;
switch (dfu_state) {
case DFU_STATE_dfuDNLOAD_SYNC:
@ -53,8 +54,7 @@ static void handle_getstatus(void)
dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
} else {
// dfu_state = DFU_STATE_dfuDNBUSY;
dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
dfu_state = DFU_STATE_dfuDNBUSY;
}
break;
}
@ -73,36 +73,149 @@ static void handle_getstate(void)
ep_transfer_send(0, (char *)&dfu_state, sizeof(dfu_state), NULL);
}
static uint8_t buf[256];
static uint16_t prog_iface;
static uint16_t prog_block;
static uint16_t prog_length;
static uint32_t prog_buf[AT91C_IFLASH_PAGE_SIZE /4];
static void handle_dnload_cb(void)
static void handle_dnload_flash(void)
{
uint32_t *ptr = (uint32_t *)((uint8_t *)0x100000 + (prog_block * 0x100));
uint32_t i;
prog_length += 3;
for (i = 0; i < prog_length /4; i++)
*ptr++ = prog_buf[i];
if (!(*AT91C_MC_FSR & AT91C_MC_FRDY)) {
printf("flash not ready!\n\r");
return;
}
*AT91C_MC_FCR = (AT91C_MC_KEY & (0x5A << 24)) |
(((uint32_t)ptr - 0x100004) & AT91C_MC_PAGEN) |
AT91C_MC_FCMD_START_PROG;
ep_transfer_send(0, NULL, 0, NULL);
}
static uint32_t handle_dnload(uint16_t index, uint16_t value, uint16_t length)
static void handle_dnload_eeprom(void)
{
printf("down:%x-%x-%x\n\r", index, value, length);
/*
* TODO: write buf to onboard eeprom @ address
* inc. address
*/
ep_transfer_send(0, NULL, 0, NULL);
}
static void handle_dnload_blctrl(void)
{
/*
* TODO: write buf to blctrl#iface @ address
* inc. address
*/
ep_transfer_send(0, NULL, 0, NULL);
}
static uint32_t handle_dnload(uint16_t iface, uint16_t block, uint16_t length)
{
printf("down:%x-%x-%x\n\r", iface, block, length);
if (length == 0) {
dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
return RET_ZLP;
}
ep_transfer_receive(0, (char *)&buf, length, handle_dnload_cb);
prog_iface = iface;
prog_block = block;
prog_length = length;
void *callback = NULL;
switch (iface) {
case 0: /* internal flash */
if (block >= 0x3C0) {
dfu_state = DFU_STATE_dfuERROR;
dfu_status = DFU_STATUS_errADDRESS;
return RET_STALL;
}
callback = handle_dnload_flash;
break;
case 1: /* onboard i2c-eeprom */
callback = handle_dnload_eeprom;
break;
case 2:
case 3:
case 4:
case 5: /* blctrl 1-4 */
callback = handle_dnload_blctrl;
break;
}
ep_transfer_receive(0, (char *)&prog_buf, length, callback);
return RET_NOTHING;
}
static uint32_t handle_upload(uint16_t index, uint16_t value, uint16_t length)
static void handle_upload(uint16_t iface, uint16_t block, uint16_t length)
{
printf("up:%x-%x-%x\n\r", index, value, length);
return 0;
printf("up:%x-%x-%x\n\r", iface, block, length);
char *ptr = (char *)&prog_buf;
switch (iface) {
case 0: /* internal flash */
if (block >= 0x400) {
length = 0;
break;
}
ptr = (char *)0x100000 + (block * 0x100);
break;
case 1: /* onboard i2c-eeprom */
if (block >= 0x80) {
length = 0;
break;
}
/* TODO */
break;
case 2:
case 3:
case 4:
case 5: /* blctrl 1-4 */
if (block >= 0x20) {
length = 0;
dfu_state = DFU_STATE_dfuIDLE;
break;
}
uint32_t i2c_dev = TWI_ADDR_BL1 + (iface -2);
struct blmc_cmd cmd = {
.cmd = (CMD_READ_FLASH << 16) | (block * 0x100),
.mode = BLMC_CMD_READ | BLMC_CMD_2_ARG,
.size = length,
.data = (uint8_t *)&prog_buf,
};
if (twi_cmd(i2c_dev, &cmd) != 0) {
length = 0;
dfu_state = DFU_STATE_dfuERROR;
dfu_status = DFU_STATUS_errUNKNOWN;
}
break;
}
ep_transfer_send(0, ptr, length, NULL);
}
void ep0_handle_dfu(struct usb_ctrlrequest *req)
{
uint32_t rc, ret = RET_NOTHING;
// printf("state:%x\n\r", dfu_state);
uint32_t ret = RET_NOTHING;
switch (dfu_state) {
case DFU_STATE_appIDLE:
@ -272,9 +385,7 @@ void ep0_handle_dfu(struct usb_ctrlrequest *req)
switch (req->bRequest) {
case USB_REQ_DFU_UPLOAD:
/* state transition if less data then requested */
rc = handle_upload(req->wIndex, req->wValue, req->wLength);
if (rc >= 0 && rc < req->wLength)
dfu_state = DFU_STATE_dfuIDLE;
handle_upload(req->wIndex, req->wValue, req->wLength);
break;
case USB_REQ_DFU_GETSTATUS: