sw: add initial tests for spi and rgb

These tests are still a work-in-progress, but they form the basis of
what will be the factory test.

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2019-05-23 09:51:45 +08:00
parent 0c8f29c7bf
commit 5ff6153b53
14 changed files with 1158 additions and 1116 deletions

File diff suppressed because it is too large Load Diff

52
sw/include/hw/common.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef __HW_COMMON_H
#define __HW_COMMON_H
#include <stdint.h>
/* To overwrite CSR accessors, define extern, non-inlined versions
* of csr_read[bwl]() and csr_write[bwl](), and define
* CSR_ACCESSORS_DEFINED.
*/
#ifndef CSR_ACCESSORS_DEFINED
#define CSR_ACCESSORS_DEFINED
#ifdef __ASSEMBLER__
#define MMPTR(x) x
#else /* ! __ASSEMBLER__ */
#define MMPTR(x) (*((volatile unsigned int *)(x)))
static inline void csr_writeb(uint8_t value, uint32_t addr)
{
*((volatile uint8_t *)addr) = value;
}
static inline uint8_t csr_readb(uint32_t addr)
{
return *(volatile uint8_t *)addr;
}
static inline void csr_writew(uint16_t value, uint32_t addr)
{
*((volatile uint16_t *)addr) = value;
}
static inline uint16_t csr_readw(uint32_t addr)
{
return *(volatile uint16_t *)addr;
}
static inline void csr_writel(uint32_t value, uint32_t addr)
{
*((volatile uint32_t *)addr) = value;
}
static inline uint32_t csr_readl(uint32_t addr)
{
return *(volatile uint32_t *)addr;
}
#endif /* ! __ASSEMBLER__ */
#endif /* ! CSR_ACCESSORS_DEFINED */
#endif /* __HW_COMMON_H */

View File

@ -6,5 +6,6 @@ void rgb_mode_idle(void);
void rgb_mode_done(void); void rgb_mode_done(void);
void rgb_mode_writing(void); void rgb_mode_writing(void);
void rgb_mode_error(void); void rgb_mode_error(void);
void rgb_mode_off(void);
#endif /* _RGB_H_ */ #endif /* _RGB_H_ */

View File

@ -50,45 +50,43 @@ struct spi_id {
struct ff_spi; struct ff_spi;
void spiPause(struct ff_spi *spi); void spiPause(void);
void spiBegin(struct ff_spi *spi); void spiBegin(void);
void spiEnd(struct ff_spi *spi); void spiEnd(void);
//void spiSingleTx(struct ff_spi *spi, uint8_t out); //void spiSingleTx(uint8_t out);
//uint8_t spiSingleRx(struct ff_spi *spi); //uint8_t spiSingleRx(void);
//void spiDualTx(struct ff_spi *spi, uint8_t out); //void spiDualTx(uint8_t out);
//void spiQuadTx(struct ff_spi *spi, uint8_t out); //void spiQuadTx(uint8_t out);
void spiCommand(struct ff_spi *spi, uint8_t cmd); void spiCommand(uint8_t cmd);
//uint8_t spiDualRx(struct ff_spi *spi); //uint8_t spiDualRx(void);
//uint8_t spiQuadRx(struct ff_spi *spi); //uint8_t spiQuadRx(void);
int spiTx(struct ff_spi *spi, uint8_t word); int spiTx(uint8_t word);
uint8_t spiRx(struct ff_spi *spi); uint8_t spiRx(void);
uint8_t spiReadStatus(struct ff_spi *spi, uint8_t sr); uint8_t spiReadStatus(uint8_t sr);
void spiWriteStatus(struct ff_spi *spi, uint8_t sr, uint8_t val); void spiWriteStatus(uint8_t sr, uint8_t val);
void spiReadSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]); void spiReadSecurity(uint8_t sr, uint8_t security[256]);
void spiWriteSecurity(struct ff_spi *spi, uint8_t sr, uint8_t security[256]); void spiWriteSecurity(uint8_t sr, uint8_t security[256]);
int spiSetType(struct ff_spi *spi, enum spi_type type); int spiSetType(enum spi_type type);
int spiRead(struct ff_spi *spi, uint32_t addr, uint8_t *data, unsigned int count); int spiRead(uint32_t addr, uint8_t *data, unsigned int count);
int spiIsBusy(struct ff_spi *spi); int spiIsBusy(void);
int spiBeginErase32(struct ff_spi *spi, uint32_t erase_addr); int spiBeginErase32(uint32_t erase_addr);
int spiBeginErase64(struct ff_spi *spi, uint32_t erase_addr); int spiBeginErase64(uint32_t erase_addr);
int spiBeginWrite(struct ff_spi *spi, uint32_t addr, const void *data, unsigned int count); int spiBeginWrite(uint32_t addr, const void *data, unsigned int count);
void spiEnableQuad(void); void spiEnableQuad(void);
struct spi_id spiId(struct ff_spi *spi); struct spi_id spiId(void);
void spiOverrideSize(struct ff_spi *spi, uint32_t new_size); void spiOverrideSize(uint32_t new_size);
//int spi_wait_for_not_busy(struct ff_spi *spi); int spiWrite(uint32_t addr, const uint8_t *data, unsigned int count);
int spiWrite(struct ff_spi *spi, uint32_t addr, const uint8_t *data, unsigned int count); uint8_t spiReset(void);
uint8_t spiReset(struct ff_spi *spi); int spi_init(void);
int spiInit(struct ff_spi *spi);
void spiHold(struct ff_spi *spi); void spiHold(void);
void spiUnhold(struct ff_spi *spi); void spiUnhold(void);
void spiSwapTxRx(struct ff_spi *spi); void spiSwapTxRx(void);
struct ff_spi *spiAlloc(void); void spiSetPin(enum spi_pin pin, int val);
void spiSetPin(struct ff_spi *spi, enum spi_pin pin, int val);
void spiFree(void); void spiFree(void);
#endif /* BB_SPI_H_ */ #endif /* BB_SPI_H_ */

View File

@ -62,7 +62,7 @@ struct usb_string_descriptor_struct {
#define PRODUCT_NAME u"Fomu Factory Test " GIT_VERSION #define PRODUCT_NAME u"Fomu Factory Test " GIT_VERSION
#define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME) #define PRODUCT_NAME_LEN sizeof(PRODUCT_NAME)
#define EP0_SIZE 64 #define EP0_SIZE 64
#define NUM_INTERFACE 1 #define NUM_INTERFACE 2
#define CONFIG_DESC_SIZE 67 #define CONFIG_DESC_SIZE 67
#define USB_DT_INTERFACE_SIZE 9 #define USB_DT_INTERFACE_SIZE 9

View File

@ -33,7 +33,7 @@ void usb_idle(void);
void usb_disconnect(void); void usb_disconnect(void);
int usb_irq_happened(void); int usb_irq_happened(void);
void usb_setup(const struct usb_setup_request *setup); int usb_setup(const struct usb_setup_request *setup);
void usb_send(const void *data, int total_count); void usb_send(const void *data, int total_count);
void usb_ack_in(void); void usb_ack_in(void);
void usb_ack_out(void); void usb_ack_out(void);

View File

@ -22,13 +22,11 @@ void isr(void)
static void init(void) static void init(void)
{ {
rgb_init(); rgb_init();
spi = spiAlloc(); spi_init();
spiInit(spi);
irq_setmask(0); irq_setmask(0);
irq_setie(1); irq_setie(1);
usb_init(); usb_init();
time_init(); time_init();
} }
int main(int argc, char **argv) int main(int argc, char **argv)

View File

@ -34,6 +34,7 @@ static enum {
WRITING, WRITING,
ERROR, ERROR,
DONE, DONE,
OFF,
} rgb_mode; } rgb_mode;
static void rgb_write(uint8_t value, uint8_t addr) { static void rgb_write(uint8_t value, uint8_t addr) {
@ -86,4 +87,8 @@ void rgb_mode_error(void) {
void rgb_mode_done(void) { void rgb_mode_done(void) {
rgb_switch_mode(DONE, 8, 8, 2, 3, 0x14/4, 0xff/4, 0x44/4); rgb_switch_mode(DONE, 8, 8, 2, 3, 0x14/4, 0xff/4, 0x44/4);
}
void rgb_mode_off(void) {
rgb_switch_mode(OFF, 0, 0, 0, 0, 0, 0, 0);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,68 @@
#include <tester.h> #include <tester.h>
#include <printf.h> #include <printf.h>
#include <spi.h>
#include <usb.h>
#include <fomu/csr.h>
#include <time.h>
#include <rgb.h>
void tester_poll(void) { int test_spi(void)
printf("Hello, world!\n"); {
return; uint8_t test_buffer[64];
uint8_t compare_buffer[sizeof(test_buffer)];
unsigned int i;
int errors = 0;
struct spi_id id = spiId();
spiSetType(ST_QUAD);
// printf("SPI Manufacturer: %02x\n", id.manufacturer_id);
// printf("SPI Device ID: %02x\n", id.device_id);
// printf("SPI Capacity: %02x %02x\n", id.memory_type, id.memory_size);
for (i = 0; i < sizeof(test_buffer); i++) {
test_buffer[i] = (i^0x9d) ^ (i<<5);
}
spiWrite(0, test_buffer, sizeof(test_buffer)-1);
for (i = 0; i < sizeof(compare_buffer); i++) {
compare_buffer[i] = 0;
}
spiRead(0, compare_buffer, sizeof(compare_buffer));
for (i = 0; i < sizeof(compare_buffer); i++) {
if (test_buffer[i] != compare_buffer[i]) {
// printf("SPI: Offset %d Expected %02x Got %02x\n", i, test_buffer[i], compare_buffer[i]);
errors++;
}
}
return errors;
}
int test_led(void) {
uint32_t pulses_per_second;
touch_oe_write(touch_oe_read() & ~(1 << 1));
// touch_oe_write(touch_oe_read() | (1 << 1));
// touch_o_write(touch_o_read() & ~(1 << 1));
rgb_bypass_write(1);
rgb_mode_off();
rgb_pwm_count_write(SYSTEM_CLOCK_FREQUENCY/1000*125);
printf("Blinking: ");
msleep(1000);
pulses_per_second = rgb_pwm_count_read();
rgb_pwm_count_write(SYSTEM_CLOCK_FREQUENCY/1000*125);
printf("%08x / %08x / %08x\n", pulses_per_second, rgb_sent_pulses_read(), rgb_detected_pulses_read());
return 0;
}
void tester_poll(void)
{
int error_count = 0;
printf("\nHello, world!\n");
// error_count = test_spi();
// printf("SPI errors: %d\n", error_count);
while (1) {
usb_poll();
test_led();
}
} }

View File

@ -16,6 +16,9 @@ void cdc_set_connected(int is_connected)
void _putchar(char character) void _putchar(char character)
{ {
if (character == '\n')
_putchar('\r');
// Wait for buffer to be empty // Wait for buffer to be empty
while (usb_ep_2_in_respond_read() == EPF_ACK) while (usb_ep_2_in_respond_read() == EPF_ACK)
; ;

View File

@ -60,7 +60,7 @@
static const uint8_t device_descriptor[] = { static const uint8_t device_descriptor[] = {
18, // bLength 18, // bLength
1, // bDescriptorType 1, // bDescriptorType
0x01, 0x02, // bcdUSB 0x10, 0x01, // bcdUSB
USB_CLASS_CDC, // bDeviceClass USB_CLASS_CDC, // bDeviceClass
0x00, // bDeviceSubClass 0x00, // bDeviceSubClass
0x00, // bDeviceProtocol 0x00, // bDeviceProtocol

View File

@ -11,11 +11,12 @@ static const int max_byte_length = 64;
#define EP2OUT_BUFFERS 4 #define EP2OUT_BUFFERS 4
__attribute__((aligned(4))) __attribute__((aligned(4)))
#define EP0OUT_BUFFER_SIZE 256 #define EP0OUT_BUFFER_SIZE 256
static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS]; // static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS];
static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFERS][EP0OUT_BUFFER_SIZE]; static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFER_SIZE];
static uint8_t volatile usb_ep0out_last_tok[EP0OUT_BUFFERS]; static int wait_reply;
static volatile uint8_t usb_ep0out_wr_ptr; static int wait_type;
static volatile uint8_t usb_ep0out_rd_ptr; // static volatile uint8_t usb_ep0out_wr_ptr;
// static volatile uint8_t usb_ep0out_rd_ptr;
#define EP2OUT_BUFFER_SIZE 256 #define EP2OUT_BUFFER_SIZE 256
static uint8_t volatile usb_ep2out_buffer_len[EP2OUT_BUFFERS]; static uint8_t volatile usb_ep2out_buffer_len[EP2OUT_BUFFERS];
@ -76,8 +77,8 @@ void usb_connect(void) {
} }
void usb_init(void) { void usb_init(void) {
usb_ep0out_wr_ptr = 0; // usb_ep0out_wr_ptr = 0;
usb_ep0out_rd_ptr = 0; // usb_ep0out_rd_ptr = 0;
usb_pullup_out_write(0); usb_pullup_out_write(0);
return; return;
} }
@ -133,8 +134,7 @@ static void process_tx(void) {
} }
void usb_send(const void *data, int total_count) { void usb_send(const void *data, int total_count) {
while ((current_length || current_data) && (usb_ep_0_in_respond_read() != EPF_NAK))
while ((current_length || current_data))// && usb_ep_0_in_respond_read() != EPF_NAK)
; ;
current_data = (uint8_t *)data; current_data = (uint8_t *)data;
current_length = total_count; current_length = total_count;
@ -157,34 +157,21 @@ void usb_isr(void) {
uint8_t ep2in_pending = usb_ep_2_in_ev_pending_read(); uint8_t ep2in_pending = usb_ep_2_in_ev_pending_read();
uint8_t ep2out_pending = usb_ep_2_out_ev_pending_read(); uint8_t ep2out_pending = usb_ep_2_out_ev_pending_read();
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
// and clear the "pending" bit.
if (ep0out_pending) {
uint8_t last_tok = usb_ep_0_out_last_tok_read();
int byte_count = 0;
usb_ep0out_last_tok[usb_ep0out_wr_ptr] = last_tok;
volatile uint8_t * obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
while (!usb_ep_0_out_obuf_empty_read()) {
obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
usb_ep_0_out_obuf_head_write(0);
}
if (byte_count >= 2)
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count - 2 /* Strip off CRC16 */;
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
if (last_tok == USB_PID_SETUP) {
usb_ep_0_in_dtb_write(1);
data_offset = 0;
current_length = 0;
current_data = NULL;
}
usb_ep_0_out_ev_pending_write(ep0out_pending);
usb_ep_0_out_respond_write(EPF_ACK);
}
// We just got an "IN" token. Send data if we have it. // We just got an "IN" token. Send data if we have it.
if (ep0in_pending) { if (ep0in_pending) {
if (wait_reply == 2) {
wait_reply--;
if (!wait_type) {
wait_type = 1;
}
}
else if (wait_reply == 1) {
if (wait_type == 2) {
current_data = NULL;
current_length = 0;
}
wait_type = 0;
}
usb_ep_0_in_respond_write(EPF_NAK); usb_ep_0_in_respond_write(EPF_NAK);
usb_ep_0_in_ev_pending_write(ep0in_pending); usb_ep_0_in_ev_pending_write(ep0in_pending);
} }
@ -200,8 +187,17 @@ void usb_isr(void) {
} }
if (ep2out_pending) { if (ep2out_pending) {
#ifdef LOOPBACK_TEST
volatile uint8_t * obuf = usb_ep2out_buffer[usb_ep2out_wr_ptr]; volatile uint8_t * obuf = usb_ep2out_buffer[usb_ep2out_wr_ptr];
int sz = 0; int sz = 0;
if (wait_reply == 2) {
wait_reply--;
wait_type = 2;
}
else if (wait_reply == 1) {
wait_reply--;
}
while (!usb_ep_2_out_obuf_empty_read()) { while (!usb_ep_2_out_obuf_empty_read()) {
if (sz < EP2OUT_BUFFER_SIZE) if (sz < EP2OUT_BUFFER_SIZE)
obuf[sz++] = usb_ep_2_out_obuf_head_read() + 1; obuf[sz++] = usb_ep_2_out_obuf_head_read() + 1;
@ -211,12 +207,40 @@ void usb_isr(void) {
usb_ep2out_buffer_len[usb_ep2out_wr_ptr] = sz - 2; /* Strip off CRC16 */ usb_ep2out_buffer_len[usb_ep2out_wr_ptr] = sz - 2; /* Strip off CRC16 */
usb_ep2out_wr_ptr = (usb_ep2out_wr_ptr + 1) & (EP2OUT_BUFFERS-1); usb_ep2out_wr_ptr = (usb_ep2out_wr_ptr + 1) & (EP2OUT_BUFFERS-1);
} }
#else // !LOOPBACK_TEST
while (!usb_ep_2_out_obuf_empty_read()) {
usb_ep_2_out_obuf_head_write(0);
}
#endif
usb_ep_2_out_respond_write(EPF_ACK); usb_ep_2_out_respond_write(EPF_ACK);
usb_ep_2_out_ev_pending_write(ep2out_pending); usb_ep_2_out_ev_pending_write(ep2out_pending);
} }
return; // We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
// and clear the "pending" bit.
if (ep0out_pending) {
unsigned int byte_count = 0;
for (byte_count = 0; byte_count < EP0OUT_BUFFER_SIZE; byte_count++)
usb_ep0out_buffer[byte_count] = 0;
byte_count = 0;
while (!usb_ep_0_out_obuf_empty_read()) {
usb_ep0out_buffer[byte_count++] = usb_ep_0_out_obuf_head_read();
usb_ep_0_out_obuf_head_write(0);
}
if (byte_count >= 2) {
usb_ep_0_in_dtb_write(1);
data_offset = 0;
current_length = 0;
current_data = NULL;
wait_reply = usb_setup((void *)usb_ep0out_buffer);
}
usb_ep_0_out_ev_pending_write(ep0out_pending);
usb_ep_0_out_respond_write(EPF_ACK);
}
process_tx();
} }
void usb_ack_in(void) { void usb_ack_in(void) {
@ -236,6 +260,7 @@ void usb_err(void) {
usb_ep_0_in_respond_write(EPF_STALL); usb_ep_0_in_respond_write(EPF_STALL);
} }
#if 0
int usb_recv(void *buffer, unsigned int buffer_len) { int usb_recv(void *buffer, unsigned int buffer_len) {
// Set the OUT response to ACK, since we are in a position to receive data now. // Set the OUT response to ACK, since we are in a position to receive data now.
@ -256,23 +281,25 @@ int usb_recv(void *buffer, unsigned int buffer_len) {
} }
return 0; return 0;
} }
#endif
void usb_poll(void) { void usb_poll(void) {
// If some data was received, then process it.
while (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]);
// uint8_t len = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
uint8_t last_tok = usb_ep0out_last_tok[usb_ep0out_rd_ptr];
// usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
if (last_tok == USB_PID_SETUP) {
usb_setup(request);
}
}
process_tx(); process_tx();
#ifdef LOOPBACK_TEST
if (usb_ep2out_rd_ptr != usb_ep2out_wr_ptr) {
volatile uint8_t *buf = usb_ep2out_buffer[usb_ep2out_rd_ptr];
unsigned int len = usb_ep2out_buffer_len[usb_ep2out_rd_ptr];
unsigned int i;
while (usb_ep_2_in_respond_read() == EPF_ACK) {
;
}
for (i = 0; i < len; i++) {
usb_ep_2_in_ibuf_head_write(buf[i]);
}
usb_ep_2_in_respond_write(EPF_ACK);
usb_ep2out_rd_ptr = (usb_ep2out_rd_ptr + 1) & (EP2OUT_BUFFERS-1);
}
#endif
} }
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */ #endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */

View File

@ -8,16 +8,30 @@
static uint8_t reply_buffer[8]; static uint8_t reply_buffer[8];
static uint8_t usb_configuration = 0; static uint8_t usb_configuration = 0;
void usb_setup(const struct usb_setup_request *setup) int usb_setup(const struct usb_setup_request *setup)
{ {
const uint8_t *data = NULL; const uint8_t *data = NULL;
uint32_t datalen = 0; uint32_t datalen = 0;
const usb_descriptor_list_t *list; const usb_descriptor_list_t *list;
uint32_t max_length = setup->wLength;//((setup->wLength >> 8) & 0xff) | ((setup->wLength << 8) & 0xff00);
switch (setup->wRequestAndType) switch (setup->wRequestAndType)
{ {
// case 0x21a1: // Get Line Coding
// reply_buffer[0] = 0x80;
// reply_buffer[1] = 0x25;
// reply_buffer[2] = 0x00;
// reply_buffer[3] = 0x00;
// reply_buffer[4] = 0x00;
// reply_buffer[5] = 0x00;
// reply_buffer[6] = 0x08;
// data = reply_buffer;
// datalen = 7;
// break;
case 0x2021: // Set Line Coding case 0x2021: // Set Line Coding
case 0x20A1: // Set Line Coding
break; break;
case 0x2221: // Set control line state case 0x2221: // Set control line state
@ -49,7 +63,7 @@ void usb_setup(const struct usb_setup_request *setup)
if (setup->wIndex > 0) if (setup->wIndex > 0)
{ {
usb_err(); usb_err();
return; return 0;
} }
reply_buffer[0] = 0; reply_buffer[0] = 0;
reply_buffer[1] = 0; reply_buffer[1] = 0;
@ -64,7 +78,7 @@ void usb_setup(const struct usb_setup_request *setup)
{ {
// TODO: do we need to handle IN vs OUT here? // TODO: do we need to handle IN vs OUT here?
usb_err(); usb_err();
return; return 0;
} }
break; break;
@ -73,7 +87,7 @@ void usb_setup(const struct usb_setup_request *setup)
{ {
// TODO: do we need to handle IN vs OUT here? // TODO: do we need to handle IN vs OUT here?
usb_err(); usb_err();
return; return 0;
} }
// XXX: Should we set the stall bit? // XXX: Should we set the stall bit?
// USB->DIEP0CTL |= USB_DIEP_CTL_STALL; // USB->DIEP0CTL |= USB_DIEP_CTL_STALL;
@ -104,20 +118,20 @@ void usb_setup(const struct usb_setup_request *setup)
} }
} }
usb_err(); usb_err();
return; return 0;
default: default:
usb_err(); usb_err();
return; return 0;
} }
send: send:
if (data && datalen) { if (data && datalen) {
if (datalen > setup->wLength) if (datalen > max_length)
datalen = setup->wLength; datalen = max_length;
usb_send(data, datalen); usb_send(data, datalen);
} }
else else
usb_ack_in(); usb_ack_in();
return; return 2;
} }