sw: getting dfu working about to add debug bridge
We're having issues getteing DFU working. It almost works, but has some issues. Unfortunately, we're out of space for printf. Now we will work to get the UART Wishbone bridge working, to move forward on debugging support. Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
b0afd2b0ae
commit
a3298226e5
@ -63,7 +63,7 @@ typedef enum {
|
|||||||
|
|
||||||
#define DFU_INTERFACE 0
|
#define DFU_INTERFACE 0
|
||||||
#define DFU_DETACH_TIMEOUT 10000 // 10 second timer
|
#define DFU_DETACH_TIMEOUT 10000 // 10 second timer
|
||||||
#define DFU_TRANSFER_SIZE 32768 // Flash sector size
|
#define DFU_TRANSFER_SIZE 256 // Flash sector size
|
||||||
|
|
||||||
// Main thread
|
// Main thread
|
||||||
void dfu_init();
|
void dfu_init();
|
||||||
|
127
sw/src/dfu.c
127
sw/src/dfu.c
@ -28,7 +28,8 @@
|
|||||||
#include <toboot-internal.h>
|
#include <toboot-internal.h>
|
||||||
#include <dfu.h>
|
#include <dfu.h>
|
||||||
|
|
||||||
#define BLOCK_SIZE 32768 // bytes
|
#define BLOCK_SIZE 32768 // Erase block size (in bytes)
|
||||||
|
#define PAGE_SIZE 256 // Number of bytes we can write
|
||||||
|
|
||||||
#include <spi.h>
|
#include <spi.h>
|
||||||
extern struct ff_spi *spi; // Defined in main.c
|
extern struct ff_spi *spi; // Defined in main.c
|
||||||
@ -72,7 +73,7 @@ static struct toboot_state {
|
|||||||
|
|
||||||
static dfu_state_t dfu_state = dfuIDLE;
|
static dfu_state_t dfu_state = dfuIDLE;
|
||||||
static dfu_status_t dfu_status = OK;
|
static dfu_status_t dfu_status = OK;
|
||||||
static unsigned dfu_poll_timeout = 100;
|
static unsigned dfu_poll_timeout = 1;
|
||||||
|
|
||||||
static uint32_t dfu_buffer[DFU_TRANSFER_SIZE/4];
|
static uint32_t dfu_buffer[DFU_TRANSFER_SIZE/4];
|
||||||
static uint32_t dfu_buffer_offset;
|
static uint32_t dfu_buffer_offset;
|
||||||
@ -86,10 +87,6 @@ static void set_state(dfu_state_t new_state, dfu_status_t new_status) {
|
|||||||
dfu_status = new_status;
|
dfu_status = new_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fl_is_idle(void) {
|
|
||||||
return fl_state == flsIDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ftfl_busy()
|
static bool ftfl_busy()
|
||||||
{
|
{
|
||||||
// Is the flash memory controller busy?
|
// Is the flash memory controller busy?
|
||||||
@ -106,12 +103,15 @@ static void ftfl_busy_wait()
|
|||||||
static void ftfl_begin_erase_sector(uint32_t address)
|
static void ftfl_begin_erase_sector(uint32_t address)
|
||||||
{
|
{
|
||||||
ftfl_busy_wait();
|
ftfl_busy_wait();
|
||||||
spiBeginErase(spi, address);
|
// Only erase if it's on the page boundry.
|
||||||
|
if ((address & ~(PAGE_SIZE - 1) ) == address)
|
||||||
|
spiBeginErase(spi, address);
|
||||||
|
fl_state = flsERASING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ftfl_write_more_bytes(void)
|
static void ftfl_write_more_bytes(void)
|
||||||
{
|
{
|
||||||
uint32_t bytes_to_write = 256;
|
uint32_t bytes_to_write = PAGE_SIZE;
|
||||||
if (dfu_bytes_remaining < bytes_to_write)
|
if (dfu_bytes_remaining < bytes_to_write)
|
||||||
bytes_to_write = dfu_bytes_remaining;
|
bytes_to_write = dfu_bytes_remaining;
|
||||||
ftfl_busy_wait();
|
ftfl_busy_wait();
|
||||||
@ -165,30 +165,30 @@ static uint32_t address_for_block(unsigned blockNum)
|
|||||||
return starting_offset + (blockNum * BLOCK_SIZE);
|
return starting_offset + (blockNum * BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If requested, erase sectors before loading new code.
|
// // If requested, erase sectors before loading new code.
|
||||||
static void pre_clear_next_block(void) {
|
// static void pre_clear_next_block(void) {
|
||||||
#pragma warning "Support for sector erasing has been disabled"
|
// #pragma warning "Support for sector erasing has been disabled"
|
||||||
#if 0
|
// #if 0
|
||||||
// If there is another sector to clear, do that.
|
// // If there is another sector to clear, do that.
|
||||||
while (++tb_state.clear_current < 64) {
|
// while (++tb_state.clear_current < 64) {
|
||||||
if (tb_state.clear_current < 32) {
|
// if (tb_state.clear_current < 32) {
|
||||||
if ((tb_state.clear_lo & (1 << tb_state.clear_current))) {
|
// if ((tb_state.clear_lo & (1 << tb_state.clear_current))) {
|
||||||
ftfl_begin_erase_sector(tb_state.clear_current * 1024);
|
// ftfl_begin_erase_sector(tb_state.clear_current * 1024);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
else if (tb_state.clear_current < 64) {
|
// else if (tb_state.clear_current < 64) {
|
||||||
if ((tb_state.clear_hi & (1 << (tb_state.clear_current & 31)))) {
|
// if ((tb_state.clear_hi & (1 << (tb_state.clear_current & 31)))) {
|
||||||
ftfl_begin_erase_sector(tb_state.clear_current * 1024);
|
// ftfl_begin_erase_sector(tb_state.clear_current * 1024);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
#endif
|
// #endif
|
||||||
// No more sectors to clear, continue with programming
|
// // No more sectors to clear, continue with programming
|
||||||
tb_state.state = tbsLOADING;
|
// tb_state.state = tbsLOADING;
|
||||||
ftfl_begin_erase_sector(tb_state.next_addr);
|
// ftfl_begin_erase_sector(tb_state.next_addr);
|
||||||
}
|
// }
|
||||||
|
|
||||||
void dfu_init(void)
|
void dfu_init(void)
|
||||||
{
|
{
|
||||||
@ -201,9 +201,9 @@ uint8_t dfu_getstate(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool dfu_download(unsigned blockNum, unsigned blockLength,
|
bool dfu_download(unsigned blockNum, unsigned blockLength,
|
||||||
unsigned packetOffset, unsigned packetLength, const uint8_t *data)
|
unsigned packetOffset, unsigned packetLength, const uint8_t *data)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
// uint32_t i;
|
||||||
|
|
||||||
if (packetOffset + packetLength > DFU_TRANSFER_SIZE ||
|
if (packetOffset + packetLength > DFU_TRANSFER_SIZE ||
|
||||||
packetOffset + packetLength > blockLength) {
|
packetOffset + packetLength > blockLength) {
|
||||||
@ -227,7 +227,7 @@ bool dfu_download(unsigned blockNum, unsigned blockLength,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ftfl_busy() || fl_state != flsIDLE) {
|
if (ftfl_busy() || (fl_state != flsIDLE)) {
|
||||||
// Flash controller shouldn't be busy now!
|
// Flash controller shouldn't be busy now!
|
||||||
set_state(dfuERROR, errUNKNOWN);
|
set_state(dfuERROR, errUNKNOWN);
|
||||||
return false;
|
return false;
|
||||||
@ -244,6 +244,7 @@ bool dfu_download(unsigned blockNum, unsigned blockLength,
|
|||||||
fl_current_addr = address_for_block(blockNum);
|
fl_current_addr = address_for_block(blockNum);
|
||||||
dfu_bytes_remaining = blockLength;
|
dfu_bytes_remaining = blockLength;
|
||||||
|
|
||||||
|
#if 0
|
||||||
// If it's the first block, figure out what we need to do in terms of erasing
|
// If it's the first block, figure out what we need to do in terms of erasing
|
||||||
// data and programming the new file.
|
// data and programming the new file.
|
||||||
if (blockNum == 0) {
|
if (blockNum == 0) {
|
||||||
@ -310,7 +311,8 @@ bool dfu_download(unsigned blockNum, unsigned blockLength,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ftfl_begin_erase_sector(fl_current_addr);
|
#endif
|
||||||
|
ftfl_begin_erase_sector(fl_current_addr);
|
||||||
|
|
||||||
set_state(dfuDNLOAD_SYNC, OK);
|
set_state(dfuDNLOAD_SYNC, OK);
|
||||||
return true;
|
return true;
|
||||||
@ -320,38 +322,33 @@ static void fl_state_poll(void)
|
|||||||
{
|
{
|
||||||
// Try to advance the state of our own flash programming state machine.
|
// Try to advance the state of our own flash programming state machine.
|
||||||
|
|
||||||
int spi_is_busy = spiIsBusy(spi);
|
if (spiIsBusy(spi))
|
||||||
|
return;
|
||||||
|
|
||||||
switch (fl_state) {
|
switch (fl_state) {
|
||||||
|
|
||||||
case flsIDLE:
|
case flsIDLE:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case flsERASING:
|
case flsERASING:
|
||||||
if (spi_is_busy)
|
// // If we're still pre-clearing, continue with that.
|
||||||
break;
|
// if (tb_state.state == tbsCLEARING) {
|
||||||
|
// pre_clear_next_block();
|
||||||
|
// }
|
||||||
|
// // Done! Move on to programming the sector.
|
||||||
|
// else {
|
||||||
|
fl_state = flsPROGRAMMING;
|
||||||
|
ftfl_begin_program_section(fl_current_addr);
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
|
||||||
// If we're still pre-clearing, continue with that.
|
case flsPROGRAMMING:
|
||||||
if (tb_state.state == tbsCLEARING) {
|
// Program more blocks, if applicable
|
||||||
pre_clear_next_block();
|
if (dfu_bytes_remaining)
|
||||||
}
|
ftfl_write_more_bytes();
|
||||||
// Done! Move on to programming the sector.
|
else
|
||||||
else {
|
fl_state = flsIDLE;
|
||||||
fl_state = flsPROGRAMMING;
|
break;
|
||||||
ftfl_begin_program_section(fl_current_addr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case flsPROGRAMMING:
|
|
||||||
if (spi_is_busy)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Program more blocks, if applicable
|
|
||||||
if (dfu_bytes_remaining)
|
|
||||||
ftfl_write_more_bytes();
|
|
||||||
else
|
|
||||||
fl_state = flsIDLE;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,9 +364,9 @@ bool dfu_getstatus(uint8_t status[8])
|
|||||||
if (dfu_state == dfuERROR) {
|
if (dfu_state == dfuERROR) {
|
||||||
// An error occurred inside fl_state_poll();
|
// An error occurred inside fl_state_poll();
|
||||||
} else if (fl_state == flsIDLE) {
|
} else if (fl_state == flsIDLE) {
|
||||||
dfu_state = dfuDNLOAD_IDLE;
|
set_state(dfuDNLOAD_IDLE, OK);
|
||||||
} else {
|
} else {
|
||||||
dfu_state = dfuDNBUSY;
|
set_state(dfuDNBUSY, OK);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ static void init(void)
|
|||||||
irq_setie(1);
|
irq_setie(1);
|
||||||
uart_init();
|
uart_init();
|
||||||
usb_init();
|
usb_init();
|
||||||
|
dfu_init();
|
||||||
time_init();
|
time_init();
|
||||||
|
|
||||||
spi = spiAlloc();
|
spi = spiAlloc();
|
||||||
@ -56,6 +57,7 @@ static void init(void)
|
|||||||
spiInit(spi);
|
spiInit(spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
static const char *usb_hw_api(void) {
|
static const char *usb_hw_api(void) {
|
||||||
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
||||||
return "epfifo";
|
return "epfifo";
|
||||||
@ -71,6 +73,7 @@ static const char *usb_hw_api(void) {
|
|||||||
#endif /* CSR_USB_OBUF_EMPTY_ADDR */
|
#endif /* CSR_USB_OBUF_EMPTY_ADDR */
|
||||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -129,10 +132,10 @@ int main(int argc, char **argv)
|
|||||||
int last = 0;
|
int last = 0;
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (usb_irq_happened() != last) {
|
// if (usb_irq_happened() != last) {
|
||||||
last = usb_irq_happened();
|
// last = usb_irq_happened();
|
||||||
// printf("USB %d IRQ happened\n", last);
|
// // printf("USB %d IRQ happened\n", last);
|
||||||
}
|
// }
|
||||||
usb_poll();
|
usb_poll();
|
||||||
/*
|
/*
|
||||||
printf("Press any key to send... ");
|
printf("Press any key to send... ");
|
||||||
|
@ -3,25 +3,25 @@
|
|||||||
|
|
||||||
#include "spi-gpio.h"
|
#include "spi-gpio.h"
|
||||||
|
|
||||||
static uint8_t do_mirror;
|
// static uint8_t do_mirror;
|
||||||
static uint8_t oe_mirror;
|
// static uint8_t oe_mirror;
|
||||||
|
|
||||||
void gpioSetMode(int pin, int mode) {
|
// void gpioSetMode(int pin, int mode) {
|
||||||
if (mode)
|
// if (mode)
|
||||||
oe_mirror |= 1 << pin;
|
// oe_mirror |= 1 << pin;
|
||||||
else
|
// else
|
||||||
oe_mirror &= ~(1 << pin);
|
// oe_mirror &= ~(1 << pin);
|
||||||
picospi_oe_write(oe_mirror);
|
// picospi_oe_write(oe_mirror);
|
||||||
}
|
// }
|
||||||
|
|
||||||
void gpioWrite(int pin, int val) {
|
// void gpioWrite(int pin, int val) {
|
||||||
if (val)
|
// if (val)
|
||||||
do_mirror |= 1 << pin;
|
// do_mirror |= 1 << pin;
|
||||||
else
|
// else
|
||||||
do_mirror &= ~(1 << pin);
|
// do_mirror &= ~(1 << pin);
|
||||||
picospi_do_write(do_mirror);
|
// picospi_do_write(do_mirror);
|
||||||
}
|
// }
|
||||||
|
|
||||||
int gpioRead(int pin) {
|
// int gpioRead(int pin) {
|
||||||
return !!(picospi_di_read() & (1 << pin));
|
// return !!(picospi_di_read() & (1 << pin));
|
||||||
}
|
// }
|
52
sw/src/spi.c
52
sw/src/spi.c
@ -7,12 +7,38 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <printf.h>
|
#include <printf.h>
|
||||||
|
#include <generated/csr.h>
|
||||||
|
|
||||||
#include "spi.h"
|
#include "spi.h"
|
||||||
#include "spi-gpio.h"
|
|
||||||
|
|
||||||
#define fprintf(...) do {} while(0)
|
#define fprintf(...) do {} while(0)
|
||||||
|
|
||||||
|
static uint8_t do_mirror;
|
||||||
|
static uint8_t oe_mirror;
|
||||||
|
|
||||||
|
#define PI_OUTPUT 1
|
||||||
|
#define PI_INPUT 0
|
||||||
|
#define PI_ALT0 PI_INPUT
|
||||||
|
static void gpioSetMode(int pin, int mode) {
|
||||||
|
if (mode)
|
||||||
|
oe_mirror |= 1 << pin;
|
||||||
|
else
|
||||||
|
oe_mirror &= ~(1 << pin);
|
||||||
|
picospi_oe_write(oe_mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gpioWrite(int pin, int val) {
|
||||||
|
if (val)
|
||||||
|
do_mirror |= 1 << pin;
|
||||||
|
else
|
||||||
|
do_mirror &= ~(1 << pin);
|
||||||
|
picospi_do_write(do_mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpioRead(int pin) {
|
||||||
|
return !!(picospi_di_read() & (1 << pin));
|
||||||
|
}
|
||||||
|
|
||||||
#define SPI_ONLY_SINGLE
|
#define SPI_ONLY_SINGLE
|
||||||
|
|
||||||
enum ff_spi_quirks {
|
enum ff_spi_quirks {
|
||||||
@ -53,6 +79,7 @@ struct ff_spi {
|
|||||||
static void spi_get_id(struct ff_spi *spi);
|
static void spi_get_id(struct ff_spi *spi);
|
||||||
|
|
||||||
static void spi_set_state(struct ff_spi *spi, enum spi_state state) {
|
static void spi_set_state(struct ff_spi *spi, enum spi_state state) {
|
||||||
|
return;
|
||||||
if (spi->state == state)
|
if (spi->state == state)
|
||||||
return;
|
return;
|
||||||
#ifndef SPI_ONLY_SINGLE
|
#ifndef SPI_ONLY_SINGLE
|
||||||
@ -317,13 +344,17 @@ uint8_t spiCommandRx(struct ff_spi *spi) {
|
|||||||
|
|
||||||
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
|
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
|
||||||
uint8_t val = 0xff;
|
uint8_t val = 0xff;
|
||||||
|
(void)sr;
|
||||||
|
|
||||||
|
#if 0
|
||||||
switch (sr) {
|
switch (sr) {
|
||||||
case 1:
|
case 1:
|
||||||
|
#endif
|
||||||
spiBegin(spi);
|
spiBegin(spi);
|
||||||
spiCommand(spi, 0x05);
|
spiCommand(spi, 0x05);
|
||||||
val = spiCommandRx(spi);
|
val = spiCommandRx(spi);
|
||||||
spiEnd(spi);
|
spiEnd(spi);
|
||||||
|
#if 0
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
@ -344,7 +375,7 @@ uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr) {
|
|||||||
fprintf(stderr, "unrecognized status register: %d\n", sr);
|
fprintf(stderr, "unrecognized status register: %d\n", sr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,6 +541,7 @@ static void spi_decode_id(struct ff_spi *spi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void spi_get_id(struct ff_spi *spi) {
|
static void spi_get_id(struct ff_spi *spi) {
|
||||||
|
#if 0
|
||||||
// memset(&spi->id, 0xff, sizeof(spi->id));
|
// memset(&spi->id, 0xff, sizeof(spi->id));
|
||||||
|
|
||||||
spiBegin(spi);
|
spiBegin(spi);
|
||||||
@ -550,6 +582,7 @@ static void spi_get_id(struct ff_spi *spi) {
|
|||||||
|
|
||||||
spi_decode_id(spi);
|
spi_decode_id(spi);
|
||||||
return;
|
return;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void spiOverrideSize(struct ff_spi *spi, uint32_t size) {
|
void spiOverrideSize(struct ff_spi *spi, uint32_t size) {
|
||||||
@ -678,12 +711,18 @@ int spiIsBusy(struct ff_spi *spi) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int spiBeginErase(struct ff_spi *spi, uint32_t erase_addr) {
|
int spiBeginErase(struct ff_spi *spi, uint32_t erase_addr) {
|
||||||
|
// Enable Write-Enable Latch (WEL)
|
||||||
|
spiBegin(spi);
|
||||||
|
spiCommand(spi, 0x06);
|
||||||
|
spiEnd(spi);
|
||||||
|
|
||||||
spiBegin(spi);
|
spiBegin(spi);
|
||||||
spiCommand(spi, 0x52);
|
spiCommand(spi, 0x52);
|
||||||
spiCommand(spi, erase_addr >> 16);
|
spiCommand(spi, erase_addr >> 16);
|
||||||
spiCommand(spi, erase_addr >> 8);
|
spiCommand(spi, erase_addr >> 8);
|
||||||
spiCommand(spi, erase_addr >> 0);
|
spiCommand(spi, erase_addr >> 0);
|
||||||
spiEnd(spi);
|
spiEnd(spi);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigned int count) {
|
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigned int count) {
|
||||||
@ -708,6 +747,8 @@ int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *v_data, unsigne
|
|||||||
for (i = 0; (i < count) && (i < 256); i++)
|
for (i = 0; (i < count) && (i < 256); i++)
|
||||||
spiTx(spi, *data++);
|
spiTx(spi, *data++);
|
||||||
spiEnd(spi);
|
spiEnd(spi);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void spiSwapTxRx(struct ff_spi *spi) {
|
void spiSwapTxRx(struct ff_spi *spi) {
|
||||||
@ -837,6 +878,13 @@ int spiInit(struct ff_spi *spi) {
|
|||||||
// Disable WP
|
// Disable WP
|
||||||
gpioWrite(spi->pins.wp, 1);
|
gpioWrite(spi->pins.wp, 1);
|
||||||
|
|
||||||
|
gpioSetMode(spi->pins.clk, PI_OUTPUT); // CLK
|
||||||
|
gpioSetMode(spi->pins.cs, PI_OUTPUT); // CE0#
|
||||||
|
gpioSetMode(spi->pins.mosi, PI_OUTPUT); // MOSI
|
||||||
|
gpioSetMode(spi->pins.miso, PI_INPUT); // MISO
|
||||||
|
gpioSetMode(spi->pins.hold, PI_OUTPUT);
|
||||||
|
gpioSetMode(spi->pins.wp, PI_OUTPUT);
|
||||||
|
|
||||||
spi_get_id(spi);
|
spi_get_id(spi);
|
||||||
|
|
||||||
spi->quirks |= SQ_SR2_FROM_SR1;
|
spi->quirks |= SQ_SR2_FROM_SR1;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
|
#include <unistd.h>
|
||||||
#include "toboot-api.h"
|
#include "toboot-api.h"
|
||||||
#include "toboot-internal.h"
|
#include "toboot-internal.h"
|
||||||
|
|
||||||
#define XXH_NO_LONG_LONG
|
// #define XXH_NO_LONG_LONG
|
||||||
#define XXH_FORCE_ALIGN_CHECK 0
|
// #define XXH_FORCE_ALIGN_CHECK 0
|
||||||
#define XXH_FORCE_NATIVE_FORMAT 0
|
// #define XXH_FORCE_NATIVE_FORMAT 0
|
||||||
#define XXH_PRIVATE_API
|
// #define XXH_PRIVATE_API
|
||||||
#include "xxhash.h"
|
// #include "xxhash.h"
|
||||||
|
|
||||||
static const struct toboot_configuration *current_config = NULL;
|
static const struct toboot_configuration *current_config = NULL;
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ uint32_t tb_generation(const struct toboot_configuration *cfg) {
|
|||||||
return 0;
|
return 0;
|
||||||
return cfg->reserved_gen;
|
return cfg->reserved_gen;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
__attribute__ ((used, section(".toboot_configuration"))) struct toboot_configuration toboot_configuration = {
|
__attribute__ ((used, section(".toboot_configuration"))) struct toboot_configuration toboot_configuration = {
|
||||||
.magic = TOBOOT_V2_MAGIC,
|
.magic = TOBOOT_V2_MAGIC,
|
||||||
|
|
||||||
@ -136,3 +137,4 @@ __attribute__ ((used, section(".toboot_configuration"))) struct toboot_configura
|
|||||||
.erase_mask_hi = 0,
|
.erase_mask_hi = 0,
|
||||||
.reserved_hash = 0,
|
.reserved_hash = 0,
|
||||||
};
|
};
|
||||||
|
*/
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
static uint8_t reply_buffer[8];
|
static uint8_t reply_buffer[8];
|
||||||
static uint8_t usb_configuration = 0;
|
static uint8_t usb_configuration = 0;
|
||||||
#define USB_MAX_PACKET_SIZE 64 /* For FS device */
|
#define USB_MAX_PACKET_SIZE 64
|
||||||
static uint8_t rx_buffer[USB_MAX_PACKET_SIZE];
|
static uint8_t rx_buffer[USB_MAX_PACKET_SIZE];
|
||||||
|
|
||||||
void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
||||||
@ -23,25 +23,26 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
|||||||
switch (setup->wRequestAndType)
|
switch (setup->wRequestAndType)
|
||||||
{
|
{
|
||||||
case 0x0500: // SET_ADDRESS
|
case 0x0500: // SET_ADDRESS
|
||||||
// TODO: Handle set_daddr
|
case 0x0b01: // SET_INTERFACE
|
||||||
// efm32hg_set_daddr(setup->wValue);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0900: // SET_CONFIGURATION
|
case 0x0900: // SET_CONFIGURATION
|
||||||
usb_configuration = setup->wValue;
|
usb_configuration = setup->wValue;
|
||||||
break;
|
break;
|
||||||
case 0x0b01: // SET_INTERFACE
|
|
||||||
break;
|
|
||||||
case 0x0880: // GET_CONFIGURATION
|
case 0x0880: // GET_CONFIGURATION
|
||||||
reply_buffer[0] = usb_configuration;
|
reply_buffer[0] = usb_configuration;
|
||||||
datalen = 1;
|
datalen = 1;
|
||||||
data = reply_buffer;
|
data = reply_buffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0080: // GET_STATUS (device)
|
case 0x0080: // GET_STATUS (device)
|
||||||
reply_buffer[0] = 0;
|
reply_buffer[0] = 0;
|
||||||
reply_buffer[1] = 0;
|
reply_buffer[1] = 0;
|
||||||
datalen = 2;
|
datalen = 2;
|
||||||
data = reply_buffer;
|
data = reply_buffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0082: // GET_STATUS (endpoint)
|
case 0x0082: // GET_STATUS (endpoint)
|
||||||
if (setup->wIndex > 0)
|
if (setup->wIndex > 0)
|
||||||
{
|
{
|
||||||
@ -58,6 +59,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
|||||||
data = reply_buffer;
|
data = reply_buffer;
|
||||||
datalen = 2;
|
datalen = 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0102: // CLEAR_FEATURE (endpoint)
|
case 0x0102: // CLEAR_FEATURE (endpoint)
|
||||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||||
{
|
{
|
||||||
@ -70,6 +72,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
|||||||
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
|
// USB->DIEP0CTL &= ~USB_DIEP_CTL_STALL;
|
||||||
// TODO: do we need to clear the data toggle here?
|
// TODO: do we need to clear the data toggle here?
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0302: // SET_FEATURE (endpoint)
|
case 0x0302: // SET_FEATURE (endpoint)
|
||||||
if (setup->wIndex > 0 || setup->wValue != 0)
|
if (setup->wIndex > 0 || setup->wValue != 0)
|
||||||
{
|
{
|
||||||
@ -82,6 +85,7 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
|||||||
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
|
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
|
||||||
// TODO: do we need to clear the data toggle here?
|
// TODO: do we need to clear the data toggle here?
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0680: // GET_DESCRIPTOR
|
case 0x0680: // GET_DESCRIPTOR
|
||||||
case 0x0681:
|
case 0x0681:
|
||||||
for (list = usb_descriptor_list; 1; list++)
|
for (list = usb_descriptor_list; 1; list++)
|
||||||
@ -156,10 +160,27 @@ void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup)
|
|||||||
usb_ack(dev, 0);
|
usb_ack(dev, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsigned int len = setup->wLength;
|
|
||||||
if (len > sizeof(rx_buffer))
|
// ACK the setup packet
|
||||||
len = sizeof(rx_buffer);
|
usb_ack(dev, 0);
|
||||||
usb_recv(dev, rx_buffer, len);
|
|
||||||
|
int bytes_remaining = setup->wLength;
|
||||||
|
int ep0_rx_offset = 0;
|
||||||
|
while (bytes_remaining > 0) {
|
||||||
|
// Fill the buffer, or if there is enough space transfer the whole packet.
|
||||||
|
unsigned int len = setup->wLength;
|
||||||
|
if (len > sizeof(rx_buffer))
|
||||||
|
len = sizeof(rx_buffer);
|
||||||
|
|
||||||
|
// Receive DATA packets (which are automatically ACKed)
|
||||||
|
usb_recv(dev, rx_buffer, len);
|
||||||
|
|
||||||
|
// Append the data to the download buffer.
|
||||||
|
dfu_download(setup->wValue, setup->wLength, ep0_rx_offset, len, rx_buffer);
|
||||||
|
|
||||||
|
bytes_remaining -= len;
|
||||||
|
ep0_rx_offset += len;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 0x03a1: // DFU_GETSTATUS
|
case 0x03a1: // DFU_GETSTATUS
|
||||||
|
@ -20,16 +20,15 @@ enum CONTROL_STATE
|
|||||||
STALLED,
|
STALLED,
|
||||||
} control_state;
|
} control_state;
|
||||||
|
|
||||||
// Note that our PIDs only have the lower nybble.
|
// Note that our PIDs are only bits 2 and 3 of the token,
|
||||||
|
// since all other bits are effectively redundant at this point.
|
||||||
enum USB_PID {
|
enum USB_PID {
|
||||||
|
USB_PID_OUT = 0,
|
||||||
|
USB_PID_SOF = 1,
|
||||||
|
USB_PID_IN = 2,
|
||||||
USB_PID_SETUP = 3,
|
USB_PID_SETUP = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_BUFFERS 4
|
|
||||||
#define BUFFER_SIZE 64
|
|
||||||
#define EP_INTERVAL_MS 6
|
|
||||||
//static const char hex[] = "0123456789abcdef";
|
|
||||||
|
|
||||||
enum epfifo_response {
|
enum epfifo_response {
|
||||||
EPF_ACK = 0,
|
EPF_ACK = 0,
|
||||||
EPF_NAK = 1,
|
EPF_NAK = 1,
|
||||||
@ -60,15 +59,15 @@ void usb_init(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
volatile int irq_count = 0;
|
static volatile int irq_count = 0;
|
||||||
|
|
||||||
#define EP0OUT_BUFFERS 4
|
#define EP0OUT_BUFFERS 8
|
||||||
__attribute__((aligned(4)))
|
__attribute__((aligned(4)))
|
||||||
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
|
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][256];
|
||||||
static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||||
static uint8_t usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
static uint8_t usb_ep0out_last_tok[EP0OUT_BUFFERS];
|
||||||
static uint8_t usb_ep0out_wr_ptr;
|
static volatile uint8_t usb_ep0out_wr_ptr;
|
||||||
static uint8_t usb_ep0out_rd_ptr;
|
static volatile uint8_t usb_ep0out_rd_ptr;
|
||||||
static const int max_byte_length = 64;
|
static const int max_byte_length = 64;
|
||||||
|
|
||||||
static const uint8_t *current_data;
|
static const uint8_t *current_data;
|
||||||
@ -104,32 +103,15 @@ static int queue_more_data(int epnum) {
|
|||||||
|
|
||||||
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) {
|
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) {
|
||||||
(void)dev;
|
(void)dev;
|
||||||
// Don't allow requeueing
|
|
||||||
// if (usb_ep_0_in_respond_read() != EPF_NAK)
|
|
||||||
// return -1;
|
|
||||||
// if (!usb_ep_0_in_ibuf_empty_read()) {
|
|
||||||
// printf("IBUF isn't empty.\n");
|
|
||||||
// return -1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
while (current_data || current_length)
|
||||||
|
;
|
||||||
current_data = (uint8_t *)data;
|
current_data = (uint8_t *)data;
|
||||||
current_length = total_count;
|
current_length = total_count;
|
||||||
current_offset = 0;
|
current_offset = 0;
|
||||||
control_state = IN_DATA;
|
control_state = IN_DATA;
|
||||||
queue_more_data(epnum);
|
queue_more_data(epnum);
|
||||||
|
|
||||||
// printf("Sending %d bytes to EP%d: [", total_count, epnum);
|
|
||||||
// int i;
|
|
||||||
// const uint8_t *u8data = data;
|
|
||||||
// for (i = 0; i < total_count; i++) {
|
|
||||||
// if (i)
|
|
||||||
// printf(" ");
|
|
||||||
|
|
||||||
// printf("%02x", u8data[i] & 0xff);
|
|
||||||
// }
|
|
||||||
// printf("]\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +119,6 @@ void usb_isr(void) {
|
|||||||
irq_count++;
|
irq_count++;
|
||||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||||
// printf(">> %02x %02x <<\n", ep0o_pending, ep0i_pending);
|
|
||||||
|
|
||||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||||
// and clear the "pending" bit.
|
// and clear the "pending" bit.
|
||||||
@ -171,17 +152,6 @@ void usb_isr(void) {
|
|||||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||||
usb_ep_0_out_respond_write(EPF_ACK);
|
usb_ep_0_out_respond_write(EPF_ACK);
|
||||||
|
|
||||||
// // Get ready to respond with an empty data byte
|
|
||||||
// if (current_offset >= current_length) {
|
|
||||||
// current_offset = 0;
|
|
||||||
// current_length = 0;
|
|
||||||
// current_data = NULL;
|
|
||||||
// if (control_state == IN_DATA) {
|
|
||||||
// usb_ep_0_out_respond_write(EPF_ACK);
|
|
||||||
// }
|
|
||||||
// usb_ep_0_out_respond_write(EPF_ACK);
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
usb_ep_0_in_respond_write(EPF_NAK);
|
usb_ep_0_in_respond_write(EPF_NAK);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -201,110 +171,68 @@ int usb_ack(struct usb_device *dev, int epnum) {
|
|||||||
(void)epnum;
|
(void)epnum;
|
||||||
usb_ep_0_out_respond_write(EPF_ACK);
|
usb_ep_0_out_respond_write(EPF_ACK);
|
||||||
usb_ep_0_in_respond_write(EPF_ACK);
|
usb_ep_0_in_respond_write(EPF_ACK);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_err(struct usb_device *dev, int epnum) {
|
int usb_err(struct usb_device *dev, int epnum) {
|
||||||
(void)dev;
|
(void)dev;
|
||||||
(void)epnum;
|
(void)epnum;
|
||||||
puts("STALLING!!!");
|
|
||||||
usb_ep_0_out_respond_write(EPF_STALL);
|
usb_ep_0_out_respond_write(EPF_STALL);
|
||||||
usb_ep_0_in_respond_write(EPF_STALL);
|
usb_ep_0_in_respond_write(EPF_STALL);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int puts_noendl(const char *s);
|
||||||
|
// static void print_eptype(void) {
|
||||||
|
// switch (usb_ep0out_last_tok[usb_ep0out_rd_ptr]) {
|
||||||
|
// case 0: puts("O"); break;
|
||||||
|
// // case 1: puts("SOF"); break;
|
||||||
|
// // case 2: puts("IN"); break;
|
||||||
|
// case 3: puts("S"); break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len) {
|
int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len) {
|
||||||
return;
|
(void)dev;
|
||||||
|
|
||||||
|
// Set the OUT response to ACK, since we are in a position to receive data now.
|
||||||
|
usb_ep_0_out_respond_write(EPF_ACK);
|
||||||
|
while (1) {
|
||||||
|
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||||
|
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_OUT) {
|
||||||
|
unsigned int ep0_buffer_len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||||
|
if (ep0_buffer_len < buffer_len)
|
||||||
|
buffer_len = ep0_buffer_len;
|
||||||
|
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||||
|
memcpy(buffer, &usb_ep0out_buffer[usb_ep0out_rd_ptr], buffer_len);
|
||||||
|
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||||
|
return buffer_len;
|
||||||
|
}
|
||||||
|
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void usb_poll(void) {
|
void usb_poll(void) {
|
||||||
// static int last_error_count;
|
|
||||||
// int this_error_count = usb_usb_transfer_error_state_read();
|
|
||||||
// if (last_error_count != this_error_count) {
|
|
||||||
// printf("USB TRANSFER ERROR STATE # %d!! WaitHand? %d WaitData? %d PID: %02x (was: %02x, full: %02x)\n", this_error_count, usb_dbg_lwh_read(), usb_dbg_lwd_read(), usb_usb_transfer_o_pid_read(), usb_usb_transfer_error_pid_read(), usb_dbg_lfp_read());
|
|
||||||
// last_error_count = this_error_count;
|
|
||||||
// }
|
|
||||||
// If some data was received, then process it.
|
// If some data was received, then process it.
|
||||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||||
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
||||||
const uint8_t *obuf = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
// unsigned int len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||||
|
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
|
||||||
|
|
||||||
if (usb_ep0out_last_tok[usb_ep0out_rd_ptr] == USB_PID_SETUP) {
|
|
||||||
// usb_ep_0_out_dtb_write(1);
|
|
||||||
// usb_ep_0_in_dtb_write(1);
|
|
||||||
usb_setup(NULL, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
int byte_count = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
|
||||||
/*
|
|
||||||
if (byte_count) {
|
|
||||||
printf("read %d %02x bytes: [", byte_count, usb_ep0out_last_tok[usb_ep0out_rd_ptr]);
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < byte_count; i++) {
|
|
||||||
if (i)
|
|
||||||
uart_write(' ');
|
|
||||||
uart_write(hex[(obuf[i] >> 4) & 0xf]);
|
|
||||||
uart_write(hex[obuf[i] & (0xf)]);
|
|
||||||
}
|
|
||||||
uart_write(']');
|
|
||||||
uart_write('\r');
|
|
||||||
uart_write('\n');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("read no bytes\n");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||||
|
|
||||||
|
if (last_tok == USB_PID_SETUP) {
|
||||||
|
usb_setup(NULL, request);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((usb_ep_0_in_respond_read() == EPF_NAK) && (current_data)) {
|
if ((usb_ep_0_in_respond_read() == EPF_NAK) && (current_data)) {
|
||||||
current_offset += current_to_send;
|
current_offset += current_to_send;
|
||||||
queue_more_data(0);
|
queue_more_data(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel any pending transfers
|
|
||||||
// if ((control_state == IN_DATA) && usb_ep_0_in_ibuf_empty_read()) {
|
|
||||||
// printf("state is IN_DATA but ibuf is empty?\n");
|
|
||||||
// usb_ack(NULL, 0);
|
|
||||||
// printf("and obuf_empty_read(): %d\n", usb_ep_0_out_obuf_empty_read());
|
|
||||||
// usb_ep_0_out_obuf_head_write(0);
|
|
||||||
// control_state = WAIT_SETUP;
|
|
||||||
// }
|
|
||||||
// if (!usb_ep_0_out_obuf_empty_read()) {
|
|
||||||
// printf("FATAL: obuf not empty, and pending is %d\n", usb_ep_0_out_ev_pending_read());
|
|
||||||
// printf("HALT");
|
|
||||||
// while (1)
|
|
||||||
// ;
|
|
||||||
// }
|
|
||||||
// if (!usb_ep_0_in_ibuf_empty_read()) {
|
|
||||||
// usb_ep_0_in_ibuf_head_write(0);
|
|
||||||
// }
|
|
||||||
// usb_ack(NULL, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
void usb_print_status(void) {
|
|
||||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
|
||||||
// printf("current_data: 0x%08x\n", current_data);
|
|
||||||
// printf("current_length: %d\n", current_length);
|
|
||||||
// printf("current_offset: %d\n", current_offset);
|
|
||||||
// printf("current_to_send: %d\n", current_to_send);
|
|
||||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
|
|
||||||
uint8_t cnt = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
|
||||||
unsigned int i;
|
|
||||||
if (cnt) {
|
|
||||||
for (i = 0; i < cnt; i++) {
|
|
||||||
uart_write(' ');
|
|
||||||
uart_write(hex[(obuf[i+1] >> 4) & 0xf]);
|
|
||||||
uart_write(hex[obuf[i+1] & (0xf)]);
|
|
||||||
}
|
|
||||||
uart_write('\r');
|
|
||||||
uart_write('\n');
|
|
||||||
}
|
|
||||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
|
||||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
Loading…
Reference in New Issue
Block a user