diff --git a/sw/include/fomu/csr.h b/sw/include/fomu/csr.h index 1e777fc..00f703a 100644 --- a/sw/include/fomu/csr.h +++ b/sw/include/fomu/csr.h @@ -1,5 +1,5 @@ //-------------------------------------------------------------------------------- -// Auto-generated by Migen (bc90344) & LiteX (3a72688b) on 2019-05-22 22:55:33 +// Auto-generated by Migen (bc90344) & LiteX (3a72688b) on 2019-05-23 14:16:56 //-------------------------------------------------------------------------------- #ifndef __GENERATED_CSR_H #define __GENERATED_CSR_H @@ -188,9 +188,9 @@ static inline unsigned char rgb_bypass_read(void) { static inline void rgb_bypass_write(unsigned char value) { csr_writel(value, 0xe000680cL); } -#define CSR_RGB_PWM_COUNT_ADDR 0xe0006810L -#define CSR_RGB_PWM_COUNT_SIZE 3 -static inline unsigned int rgb_pwm_count_read(void) { +#define CSR_RGB_PULSE_ADDR 0xe0006810L +#define CSR_RGB_PULSE_SIZE 3 +static inline unsigned int rgb_pulse_read(void) { unsigned int r = csr_readl(0xe0006810L); r <<= 8; r |= csr_readl(0xe0006814L); @@ -198,33 +198,48 @@ static inline unsigned int rgb_pwm_count_read(void) { r |= csr_readl(0xe0006818L); return r; } -static inline void rgb_pwm_count_write(unsigned int value) { +static inline void rgb_pulse_write(unsigned int value) { csr_writel(value >> 16, 0xe0006810L); csr_writel(value >> 8, 0xe0006814L); csr_writel(value, 0xe0006818L); } -#define CSR_RGB_SENT_PULSES_ADDR 0xe000681cL -#define CSR_RGB_SENT_PULSES_SIZE 4 -static inline unsigned int rgb_sent_pulses_read(void) { +#define CSR_RGB_DUTY_ADDR 0xe000681cL +#define CSR_RGB_DUTY_SIZE 3 +static inline unsigned int rgb_duty_read(void) { unsigned int r = csr_readl(0xe000681cL); r <<= 8; r |= csr_readl(0xe0006820L); r <<= 8; r |= csr_readl(0xe0006824L); - r <<= 8; - r |= csr_readl(0xe0006828L); return r; } -#define CSR_RGB_DETECTED_PULSES_ADDR 0xe000682cL -#define CSR_RGB_DETECTED_PULSES_SIZE 4 -static inline unsigned int rgb_detected_pulses_read(void) { - unsigned int r = csr_readl(0xe000682cL); +static inline void rgb_duty_write(unsigned int value) { + csr_writel(value >> 16, 0xe000681cL); + csr_writel(value >> 8, 0xe0006820L); + csr_writel(value, 0xe0006824L); +} +#define CSR_RGB_SENT_PULSES_ADDR 0xe0006828L +#define CSR_RGB_SENT_PULSES_SIZE 4 +static inline unsigned int rgb_sent_pulses_read(void) { + unsigned int r = csr_readl(0xe0006828L); + r <<= 8; + r |= csr_readl(0xe000682cL); r <<= 8; r |= csr_readl(0xe0006830L); r <<= 8; r |= csr_readl(0xe0006834L); + return r; +} +#define CSR_RGB_DETECTED_PULSES_ADDR 0xe0006838L +#define CSR_RGB_DETECTED_PULSES_SIZE 4 +static inline unsigned int rgb_detected_pulses_read(void) { + unsigned int r = csr_readl(0xe0006838L); r <<= 8; - r |= csr_readl(0xe0006838L); + r |= csr_readl(0xe000683cL); + r <<= 8; + r |= csr_readl(0xe0006840L); + r <<= 8; + r |= csr_readl(0xe0006844L); return r; } diff --git a/sw/include/usb-cdc.h b/sw/include/usb-cdc.h index 63b2b9e..e971bf8 100644 --- a/sw/include/usb-cdc.h +++ b/sw/include/usb-cdc.h @@ -160,6 +160,11 @@ struct usb_cdc_notification { int cdc_connected(); void cdc_set_connected(int is_connected); +void put_hex(uint32_t val); +void put_hex_byte(uint8_t val); +void put_string(const char *str); +void put_char(char character); +void flush_serial(void); #endif diff --git a/sw/src/tester.c b/sw/src/tester.c index 8f00158..fb4b5d0 100644 --- a/sw/src/tester.c +++ b/sw/src/tester.c @@ -1,12 +1,12 @@ #include -#include +#include #include #include #include #include #include -int test_spi(void) +static uint32_t test_spi(void) { uint8_t test_buffer[64]; uint8_t compare_buffer[sizeof(test_buffer)]; @@ -15,54 +15,193 @@ int test_spi(void) 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); + put_string("SPI: Manufacturer "); + put_hex_byte(id.manufacturer_id); + put_string(" / "); - for (i = 0; i < sizeof(test_buffer); i++) { - test_buffer[i] = (i^0x9d) ^ (i<<5); + put_string("Device ID "); + put_hex_byte(id.device_id); + put_string(" / "); + + put_string("Capacity "); + put_hex_byte(id.memory_type); + put_char(' '); + put_hex_byte(id.memory_size); + put_string(" / "); + + put_string("Serial "); + put_hex(*((uint32_t *)id.serial)); + put_string(" / "); + + for (i = 0; i < sizeof(test_buffer); i++) + { + test_buffer[i] = (i ^ 0x9d) ^ (i << 5); } - spiWrite(0, test_buffer, sizeof(test_buffer)-1); + spiWrite(0, test_buffer, sizeof(test_buffer)); - for (i = 0; i < sizeof(compare_buffer); i++) { + 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]) { + for (i = 0; i < sizeof(compare_buffer); i++) + { + if (test_buffer[i] != compare_buffer[i]) + { + put_string("E@"); + put_hex_byte(i); + put_char(':'); + put_hex_byte(test_buffer[i]); + put_char('!'); + put_hex_byte(compare_buffer[i]); + put_char(' '); // printf("SPI: Offset %d Expected %02x Got %02x\n", i, test_buffer[i], compare_buffer[i]); errors++; } } + if (!errors) + { + put_string("Pass\n"); + } + else + { + put_string("FAIL\n"); + } return errors; } -int test_led(void) { +static uint32_t test_one_pad(uint8_t src, uint8_t dest) +{ + unsigned int loops; + unsigned int matches = 0; + const unsigned int loop_max = 10; + + put_char('0'+src); + put_char('>'); + put_char('0'+dest); + put_char(':'); + for (loops = 0; loops < loop_max; loops++) { + // Set pin 2 as output, and pin 0 as input, and see if it loops back. + touch_oe_write((1 << src) | (0 << dest)); + touch_o_write((loops&1) << src); + if ((loops&1) == !!((touch_i_read() & (1 << dest)))) + matches++; + } + if (matches == loop_max) { + put_string("OK "); + return 0; + } + else { + put_string("FAIL("); + put_hex_byte(loop_max); + put_char('!'); + put_hex_byte(matches); + put_string(") "); + return (loop_max - matches); + } +} + +static uint32_t test_touch(void) +{ + uint32_t error_count = 0; + + put_string("Touch: "); + + error_count += test_one_pad(0, 2); + error_count += test_one_pad(0, 3); + error_count += test_one_pad(2, 0); + error_count += test_one_pad(2, 3); + error_count += test_one_pad(3, 0); + error_count += test_one_pad(3, 2); + + if (error_count) + put_string("FAIL\n"); + else + put_string("Pass\n"); + return error_count; +} + +static const char color_names[] = {'B', 'R', 'G'}; + +static uint32_t test_one_color(int color) +{ uint32_t pulses_per_second; + uint32_t sent_pulses; + uint32_t detected_pulses; + uint32_t high_value; + + rgb_bypass_write(1 << color); + rgb_mode_off(); + rgb_duty_write(SYSTEM_CLOCK_FREQUENCY / 10000 * 1); + rgb_pulse_write(SYSTEM_CLOCK_FREQUENCY / 1000 * 1); + put_string("RGB"); + put_char(color_names[color]); + put_string(": "); + msleep(100); + + rgb_pulse_write(SYSTEM_CLOCK_FREQUENCY / 1000 * 1); + pulses_per_second = rgb_pulse_read(); + high_value = rgb_duty_read(); + sent_pulses = rgb_sent_pulses_read(); + detected_pulses = rgb_detected_pulses_read(); + + put_hex(pulses_per_second); + put_string(" / "); + put_hex(high_value); + put_string(" / "); + put_hex(sent_pulses); + put_string(" / "); + put_hex(detected_pulses); + put_string(" / "); + rgb_bypass_write(0); + + uint32_t ratio = ((detected_pulses * 100) / sent_pulses); + put_string("Ratio: 0x"); + put_hex(ratio); + put_string(" / "); + if (ratio > 60) + { + put_string("Pass\n"); + return 0; + } + + put_string("FAIL\n"); + return 1 + ratio; +} + +static uint32_t test_led(void) +{ + uint32_t error_count = 0; + 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; + + error_count += test_one_color(0); + error_count += test_one_color(1); + error_count += test_one_color(2); + return error_count; } 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) { + put_string("\nHello, world!\n"); + error_count += test_spi(); + error_count += test_led(); + error_count += test_touch(); + + put_string("FOMU: "); + put_hex(error_count); + put_string(" errors "); + if (error_count) + put_string("FAIL!\n"); + else + put_string("Pass\n"); + while (1) + { usb_poll(); - test_led(); } } \ No newline at end of file diff --git a/sw/src/usb-cdc.c b/sw/src/usb-cdc.c index 1722038..ecc542b 100644 --- a/sw/src/usb-cdc.c +++ b/sw/src/usb-cdc.c @@ -3,6 +3,10 @@ #include static int connected = 0; +struct str_bfr +{ + uint8_t bfr_contents; +} str_bfr; int cdc_connected(void) { @@ -24,4 +28,71 @@ void _putchar(char character) ; usb_ep_2_in_ibuf_head_write(character); usb_ep_2_in_respond_write(EPF_ACK); +} + +void flush_serial(void) +{ + if (!str_bfr.bfr_contents) + return; + + usb_ep_2_in_respond_write(EPF_ACK); + // Wait for buffer to be empty + while (usb_ep_2_in_respond_read() == EPF_ACK) + ; + str_bfr.bfr_contents = 0; +} + +void add_char_to_buffer(char character) +{ + while (usb_ep_2_in_respond_read() == EPF_ACK) + ; + usb_ep_2_in_ibuf_head_write(character); + str_bfr.bfr_contents++; + if (str_bfr.bfr_contents >= 64) + flush_serial(); +} + +void put_string(const char *str) +{ + while (*str != '\0') + { + if (*str == '\n') + add_char_to_buffer('\r'); + add_char_to_buffer(*str); + str++; + } + flush_serial(); +} + +void put_hex(uint32_t val) +{ + int num_nibbles = sizeof(val) * 2; + + do + { + char v = '0' + (((val >> (num_nibbles - 1) * 4)) & 0x0f); + if (v > '9') + v += 'a' - ('9'+1); + put_char(v); + } while (--num_nibbles); +} + +void put_hex_byte(uint8_t val) +{ + int num_nibbles = sizeof(val) * 2; + + do + { + char v = '0' + (((val >> (num_nibbles - 1) * 4)) & 0x0f); + if (v > '9') + v += 'a' - ('9'+1); + put_char(v); + } while (--num_nibbles); +} + +void put_char(char character) +{ + if (character == '\n') + add_char_to_buffer('\r'); + add_char_to_buffer(character); } \ No newline at end of file diff --git a/sw/src/usb-epfifo.c b/sw/src/usb-epfifo.c index 2168886..5885f6c 100644 --- a/sw/src/usb-epfifo.c +++ b/sw/src/usb-epfifo.c @@ -7,16 +7,12 @@ static const int max_byte_length = 64; -#define EP0OUT_BUFFERS 4 #define EP2OUT_BUFFERS 4 -__attribute__((aligned(4))) #define EP0OUT_BUFFER_SIZE 256 -// static uint8_t volatile usb_ep0out_buffer_len[EP0OUT_BUFFERS]; -static uint8_t volatile usb_ep0out_buffer[EP0OUT_BUFFER_SIZE]; +__attribute__((aligned(4))) +static uint8_t volatile usb_ep0out_buffer[64 + 2]; static int wait_reply; static int wait_type; -// static volatile uint8_t usb_ep0out_wr_ptr; -// static volatile uint8_t usb_ep0out_rd_ptr; #define EP2OUT_BUFFER_SIZE 256 static uint8_t volatile usb_ep2out_buffer_len[EP2OUT_BUFFERS]; @@ -220,21 +216,35 @@ void usb_isr(void) { // 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; + for (byte_count = 0; byte_count < sizeof(usb_ep0out_buffer); 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(); + uint8_t byte = usb_ep_0_out_obuf_head_read(); usb_ep_0_out_obuf_head_write(0); + usb_ep0out_buffer[byte_count++] = byte; } if (byte_count >= 2) { + volatile void *setup_buffer = usb_ep0out_buffer; usb_ep_0_in_dtb_write(1); data_offset = 0; current_length = 0; current_data = NULL; - wait_reply = usb_setup((void *)usb_ep0out_buffer); + byte_count -= 2; + // XXX TERRIBLE HACK! + // Because the epfifo backend doesn't have any concept of packet boundaries, + // sometimes one or two of the bytes from the CRC on the "ACK" from the previous + // "Get Descriptor" will be stuck on the front of this request. + // This can happen if, for example, we get the OUT from that and the OUT from + // the subsequent SETUP packet without first handling that. + // Since all SETUP packets are 8 bytes (in this tester), we'll simply clamp the + // SETUP data packet to be the last 8 bytes received (minus the 2-byte CRC16). + // This is horrible and should be fixed in hardware. + if (byte_count > 8) + setup_buffer += byte_count - 8; + wait_reply = usb_setup((const struct usb_setup_request *)setup_buffer); } usb_ep_0_out_ev_pending_write(ep0out_pending); usb_ep_0_out_respond_write(EPF_ACK);