diff options
Diffstat (limited to 'firmware')
34 files changed, 1882 insertions, 1485 deletions
diff --git a/firmware/fx3/b200/b200_gpifconfig.h b/firmware/fx3/b200/b200_gpifconfig.h index 58836fac8..a6a24e0c5 100644..100755 --- a/firmware/fx3/b200/b200_gpifconfig.h +++ b/firmware/fx3/b200/b200_gpifconfig.h @@ -1,10 +1,6 @@ -//
-// Copyright 2013-2014 Ettus Research LLC
-//
-
/*
- * Project Name: b200_v2.cyfx
- * Time : 01/17/2013 12:50:08
+ * Project Name: ssf2-edit.cyfx
+ * Time : 11/17/2014 13:01:01
* Device Type: FX3
* Project Type: GPIF2
*
@@ -13,7 +9,7 @@ *
* This is a generated file and should not be modified
* This file need to be included only once in the firmware
- * This file is generated by Gpif2 designer tool version - 1.0.715.0
+ * This file is generated by Gpif2 designer tool version - 1.0.837.1
*
*/
@@ -25,7 +21,7 @@ /* Summary
Number of states in the state machine
*/
-#define CY_NUMBER_OF_STATES 6
+#define CY_NUMBER_OF_STATES 7
/* Summary
Mapping of user defined state names to state indices
@@ -36,12 +32,13 @@ #define WRITE 3
#define SHORT_PKT 4
#define ZLP 5
+#define DSS_STATE 6
/* Summary
Initial value of early outputs from the state machine.
*/
-#define ALPHA_RESET 0x8
+#define ALPHA_RESET 0xC
/* Summary
@@ -58,26 +55,27 @@ uint16_t CyFxGpifTransition[] = { waveform table.
*/
CyU3PGpifWaveData CyFxGpifWavedata[] = {
- {{0x1E086001,0x000100C4,0x80000000},{0x00000000,0x00000000,0x00000000}},
- {{0x4E080302,0x00000200,0x80000000},{0x00000000,0x00000000,0x00000000}},
- {{0x1E086001,0x000100C4,0x80000000},{0x4E040704,0x20000200,0xC0100000}},
+ {{0x1E086001,0x000302C4,0x80000000},{0x00000000,0x00000000,0x00000000}},
+ {{0x4E080302,0x00000300,0x80000000},{0x1E086006,0x000302C4,0x80000000}},
+ {{0x1E086001,0x000302C4,0x80000000},{0x4E040704,0x20000300,0xC0100000}},
+ {{0x4E080302,0x00000300,0x80000000},{0x1E086001,0x000302C4,0x80000000}},
{{0x00000000,0x00000000,0x00000000},{0x00000000,0x00000000,0x00000000}},
- {{0x00000000,0x00000000,0x00000000},{0x3E738705,0x00000200,0xC0100000}},
- {{0x00000000,0x00000000,0x00000000},{0x5E002703,0x2001020C,0x80000000}},
- {{0x00000000,0x00000000,0x00000000},{0x4E040704,0x20000200,0xC0100000}}
+ {{0x00000000,0x00000000,0x00000000},{0x3E738705,0x00000300,0xC0100000}},
+ {{0x00000000,0x00000000,0x00000000},{0x5E002703,0x2003030C,0x80000000}},
+ {{0x00000000,0x00000000,0x00000000},{0x4E040704,0x20000300,0xC0100000}}
};
/* Summary
Table that maps state indices to the descriptor table indices.
*/
uint8_t CyFxGpifWavedataPosition[] = {
- 0,1,0,2,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 0,4,0,2,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 0,5,0,2,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 0,6,0,2,0,0
+ 0,1,0,2,0,0,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 0,5,0,2,0,0,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 0,6,0,2,0,0,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+ 0,7,0,2,0,0,7
};
/* Summary
@@ -154,12 +152,12 @@ uint32_t CyFxGpifRegValue[] = { 0x00000000, /* CY_U3P_PIB_GPIF_LAMBDA_STAT */
0x00000000, /* CY_U3P_PIB_GPIF_ALPHA_STAT */
0x00000000, /* CY_U3P_PIB_GPIF_BETA_STAT */
- 0x00080000, /* CY_U3P_PIB_GPIF_WAVEFORM_CTRL_STAT */
+ 0x000C0000, /* CY_U3P_PIB_GPIF_WAVEFORM_CTRL_STAT */
0x00000000, /* CY_U3P_PIB_GPIF_WAVEFORM_SWITCH */
0x00000000, /* CY_U3P_PIB_GPIF_WAVEFORM_SWITCH_TIMEOUT */
0x00000000, /* CY_U3P_PIB_GPIF_CRC_CONFIG */
0x00000000, /* CY_U3P_PIB_GPIF_CRC_DATA */
- 0xFFFFFFF1 /* CY_U3P_PIB_GPIF_BETA_DEASSERT */
+ 0xFFFFFFC1 /* CY_U3P_PIB_GPIF_BETA_DEASSERT */
};
/* Summary
diff --git a/firmware/fx3/b200/b200_main.c b/firmware/fx3/b200/b200_main.c index cb0172af3..e552d3177 100644 --- a/firmware/fx3/b200/b200_main.c +++ b/firmware/fx3/b200/b200_main.c @@ -1,5 +1,5 @@ // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 2013-2015 Ettus Research LLC // /* This file defines the application that runs on the Cypress FX3 device, and @@ -34,18 +34,19 @@ * Indented features must have the parent feature enabled as well. */ -//#define HAS_HEAP // This requires memory to be set aside for the heap (e.g. required for printing floating-point numbers). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to create one. -//#define ENABLE_MSG // This will cause the compiled code to exceed the default text memory area (SYS_MEM). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to resize the memory map so it will fit. -//#define ENABLE_MANUAL_DMA_XFER -//#define ENABLE_MANUAL_DMA_XFER_FROM_HOST -//#define ENABLE_MANUAL_DMA_XFER_TO_HOST +#define HAS_HEAP // This requires memory to be set aside for the heap (e.g. required for printing floating-point numbers). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to create one. +#define ENABLE_MSG // This will cause the compiled code to exceed the default text memory area (SYS_MEM). You can apply the accompanying patch ('fx3_mem_map.patch') to fx3.ld & cyfxtx.c to resize the memory map so it will fit. +#define ENABLE_MANUAL_DMA_XFER // Allows us to set it from the host (using the side channel util), doesn't auto-enable it +//#define ENABLE_P2U_SUSP_EOP +#define ENABLE_MANUAL_DMA_XFER_FROM_HOST +#define ENABLE_MANUAL_DMA_XFER_TO_HOST //#define ENABLE_DMA_BUFFER_PACKET_DEBUG -//#define ENABLE_FPGA_SB // Be careful: this will add an ever-so-slight delay to some operations (e.g. AD3961 tune) +#define ENABLE_FPGA_SB // Be careful: this will add an ever-so-slight delay to some operations (e.g. AD3961 tune) #define ENABLE_RE_ENUM_THREAD #define ENABLE_USB_EVENT_LOGGING //#define PREVENT_LOW_POWER_MODE -//#define ENABLE_INIT_B_WORKAROUND // This should only be enabled if you have a board where the FPGA INIT_B line is broken, but the FPGA is known to work -//#define ENABLE_DONE_WORKAROUND // This should only be enabled if you have a board where the FPGA DONE line is broken, but the FPGA is known to work +/*#define ENABLE_INIT_B_WORKAROUND // This should only be enabled if you have a board where the FPGA INIT_B line is broken, but the FPGA is known to work*/ +/*#define ENABLE_DONE_WORKAROUND // This should only be enabled if you have a board where the FPGA DONE line is broken, but the FPGA is known to work*/ #define WATCHDOG_TIMEOUT 1500 #define CHECK_POWER_STATE_SLEEP_TIME 500 // Should be less than WATCHDOG_TIMEOUT @@ -178,7 +179,7 @@ static uint8_t g_usb_event_log_contiguous_buf[USB_EVENT_LOG_SIZE]; #ifdef ENABLE_FPGA_SB static CyBool_t g_fpga_sb_enabled = CyFalse; -static uint16_t g_fpga_sb_uart_div = 434*2; +//static uint16_t g_fpga_sb_uart_div = 434*2; static uint16_t g_fpga_sb_last_usb_event_log_index = 0; static CyU3PThread thread_fpga_sb_poll; static CyU3PMutex g_suart_lock; @@ -215,7 +216,8 @@ enum ConfigFlags { CF_DMA_BUFFER_SIZE = 1 << 5, CF_DMA_BUFFER_COUNT = 1 << 6, CF_MANUAL_DMA = 1 << 7, - + CF_SB_BAUD_DIV = 1 << 8, + CF_RE_ENUM = 1 << 31 }; @@ -236,7 +238,17 @@ typedef struct ConfigMod { CONFIG config; } CONFIG_MOD, *PCONFIG_MOD; -static CONFIG g_config; +static CONFIG g_config = { + 65, // tx_swing + 0x11, // tx_deemphasis + 0, // disable_usb2 + 1, // enable_as_superspeed + CY_U3P_DS_THREE_QUARTER_STRENGTH, // pport_drive_strength + 64512, // dma_buffer_size 2**16-1, then aligned to next page boundary + 1, // dma_buffer_count + 0, // manual_dma + 434*2 // sb_baud_div +}; static CONFIG_MOD g_config_mod; #define REG_LNK_PHY_ERROR_STATUS 0xE0033044 @@ -251,7 +263,7 @@ enum PhyErrors { PHYERR_PHY_ERROR_EB_UND_EV = 1 << 2, PHYERR_PHY_ERROR_EB_OVR_EV = 1 << 1, PHYERR_PHY_ERROR_DECODE_EV = 1 << 0, - + PHYERR_MAX = PHYERR_PHY_LOCK_EV, PHYERR_MASK = (PHYERR_MAX << 1) - 1 }; @@ -259,7 +271,7 @@ enum PhyErrors { typedef struct USBErrorCounters { int phy_error_count; int link_error_count; - + int PHY_LOCK_EV; int TRAINING_ERROR_EV; int RX_ERROR_CRC32_EV; @@ -281,35 +293,45 @@ typedef struct DMACounters { int ERROR; int PROD_SUSP; int CONS_SUSP; - + int BUFFER_MARKER; int BUFFER_EOP; int BUFFER_ERROR; int BUFFER_OCCUPIED; - + int last_count; int last_size; - + int last_sid; int bad_sid_count; } DMA_COUNTERS, *PDMA_COUNTERS; +typedef struct PIBCounters +{ + int socket_inactive; // CYU3P_PIB_ERR_THR1_SCK_INACTIVE +} PIB_COUNTERS, *PPIB_COUNTERS; + typedef struct Counters { int magic; - + DMA_COUNTERS dma_to_host; DMA_COUNTERS dma_from_host; - + int log_overrun_count; - + int usb_error_update_count; - USB_ERROR_COUNTERS usb_error_counters; - + USB_ERROR_COUNTERS usb_error_counters; + int usb_ep_underrun_count; - + int heap_size; - + int resume_count; + + int state_transition_count; + int invalid_gpif_state; + + PIB_COUNTERS pib_counters[4]; } COUNTERS, *PCOUNTERS; volatile static COUNTERS g_counters; @@ -333,7 +355,7 @@ caddr_t _sbrk(int incr) extern char __heap_end; char *prev_heap_end; - if (heap_end == 0) + if (heap_end == 0) { heap_end = (char *)&__heap_start; } @@ -366,15 +388,15 @@ void msg(const char* str, ...) { va_list args; static char buf[LOG_BUFFER_SIZE]; int idx = 0; - + msg_CHECK_USE_LOCK LOCK(g_log_lock); - + ++log_count; log_count %= 10000; va_start(args, str); - + if (1) { // FIXME: Optional uint32_t time_now = CyU3PGetTime(); idx += sprintf(buf, "%08X %04i ", (uint)time_now, log_count); @@ -382,19 +404,19 @@ void msg(const char* str, ...) { else idx += sprintf(buf, "%04i ", log_count); idx += vsnprintf(buf + idx, LOG_BUFFER_SIZE - idx, str, args); - + va_end(args); - + if ((LOG_BUFFER_SIZE - log_buffer_len) < (idx + 1 + 1)) { msg_CHECK_USE_LOCK LOCK(g_counters_lock); ++g_counters.log_overrun_count; msg_CHECK_USE_LOCK UNLOCK(g_counters_lock); - + goto msg_exit; } - + // Circular buffer if we need it later, but currently won't wrap due to above condition memcpy(log_buffer + log_buffer_len, buf, min(idx + 1, LOG_BUFFER_SIZE - log_buffer_len)); if ((idx + 1) > (LOG_BUFFER_SIZE - log_buffer_len)) @@ -404,7 +426,7 @@ void msg(const char* str, ...) { } else log_buffer[log_buffer_len + idx + 1] = '\0'; - + log_buffer_len += (idx + 1); msg_exit: msg_CHECK_USE_LOCK @@ -437,42 +459,42 @@ void msg_nl(const char* str, ...) */ void log_reset(void) { //LOCK(g_log_lock); - + log_buffer_idx = 0; - log_buffer_len = 0; + log_buffer_len = 0; log_buffer[0] = '\0'; - + //UNLOCK(g_log_lock); } void counters_auto_reset(void) { //LOCK(g_counters_lock); - - g_counters.log_overrun_count = 0; - + + g_counters.log_overrun_count = 0; + //UNLOCK(g_counters_lock); } void counters_dma_reset(void) { LOCK(g_counters_lock); - + LOCK(g_counters_dma_to_host_lock); memset((void*)&g_counters.dma_to_host, 0x00, sizeof(DMA_COUNTERS)); UNLOCK(g_counters_dma_to_host_lock); - + LOCK(g_counters_dma_from_host_lock); memset((void*)&g_counters.dma_from_host, 0x00, sizeof(DMA_COUNTERS)); UNLOCK(g_counters_dma_from_host_lock); - + UNLOCK(g_counters_lock); } void counters_reset_usb_errors(void) { LOCK(g_counters_lock); - + g_counters.usb_error_update_count = 0; memset((void*)&g_counters.usb_error_counters, 0x00, sizeof(g_counters.usb_error_counters)); - + UNLOCK(g_counters_lock); } @@ -485,10 +507,10 @@ void dma_callback ( int from_host) { CyU3PReturnStatus_t status = CY_U3P_SUCCESS; - + PDMA_COUNTERS cnt = (PDMA_COUNTERS)(from_host ? &g_counters.dma_from_host : &g_counters.dma_to_host); CyU3PMutex* lock = (from_host ? &g_counters_dma_from_host_lock : &g_counters_dma_to_host_lock); - + uint16_t buffer_status = (input->buffer_p.status & CY_U3P_DMA_BUFFER_STATUS_MASK); if (buffer_status & CY_U3P_DMA_BUFFER_MARKER) { @@ -513,49 +535,51 @@ void dma_callback ( LOCKP(lock); int prod_cnt = cnt->PROD_EVENT++; UNLOCKP(lock); - - if (cnt->last_count != input->buffer_p.count) - msg("[DMA %05d] buffer.count (%d) != last_count (%d)", prod_cnt, input->buffer_p.count, cnt->last_count); + + //if (cnt->last_count != input->buffer_p.count) + // msg("[DMA%d %05d] buffer.count (%05d) != last_count (%05d)", from_host, prod_cnt, input->buffer_p.count, cnt->last_count); cnt->last_count = input->buffer_p.count; - + if (cnt->last_size != input->buffer_p.size) - msg("[DMA %05d] buffer.size (%d) != last_size (%d)", prod_cnt, input->buffer_p.size, cnt->last_size); + msg("[DMA%d %05d] buffer.size (%05d) != last_size (%05d)", from_host, prod_cnt, input->buffer_p.size, cnt->last_size); cnt->last_size = input->buffer_p.size; - + uint32_t* p32 = input->buffer_p.buffer; uint32_t sid = p32[1]; cnt->last_sid = (int)sid; - if ((sid != 0xa0) && (sid != 0xb0)) + if (((from_host == 0) && ((sid != 0xa0) && (sid != 0xb0))) || + ((from_host == 1) && ((sid != 0x50) && (sid != 0x60)))) { cnt->bad_sid_count++; - msg("[DMA %05d] Bad SID: 0x%08x", prod_cnt, sid); + msg("[DMA%d %05d] Bad SID: 0x%08x", from_host, prod_cnt, sid); } - + uint16_t* p16 = input->buffer_p.buffer; - + if (p32[0] & (((uint32_t)1) << 31)) { - msg("[DMA %05d] Error code: 0x%x (packet len: %d)", prod_cnt, p32[4], p16[0]); // Status - - //msg("[DMA] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); + msg("[DMA%d %05d] Error code: 0x%x (packet len: %05d, buffer count: %05d, seq: %04d)", from_host, prod_cnt, p32[4], p16[0], input->buffer_p.count, (p16[1] & 0x0fff)); // Status + + //msg("[DMA%d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", from_host, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); } else - { + { if (p16[1] & (((uint16_t)1) << 12)) { - msg("[DMA %05d] EOB", prod_cnt); // Comes with one sample + msg("[DMA%d %05d] EOB (packet len: %05d, buffer count: %05d)", from_host, prod_cnt, p16[0], input->buffer_p.count); // Comes with one sample } - + if ((p16[0] != input->buffer_p.count) && - ((p16[0] + 4) != input->buffer_p.count)) + ((p16[0] + 4) != input->buffer_p.count)) // Case of overrun packet length being padded (being rounded up) { - msg("[DMA %05d] Packet len (%d) != buffer count (%d)", prod_cnt, p16[0], input->buffer_p.count); + if (from_host == 0) + msg("[DMA%d %05d] Packet len (%05d) != buffer count (%05d), seq: %04d [0x%04x 0x%04x]", from_host, prod_cnt, p16[0], input->buffer_p.count, (p16[1] & 0x0fff), p16[0], p16[1]); } - - //msg("[DMA] 0x%04x 0x%04x 0x%04x 0x%04x", p16[0], p16[1], p16[2], p16[3]); - + + //msg("[DMA%d] 0x%04x 0x%04x 0x%04x 0x%04x", from_host, p16[0], p16[1], p16[2], p16[3]); + if (p16[1] & (((uint16_t)1) << 12)) - msg("[DMA %05d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", prod_cnt, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); + msg("[DMA%d %05d] 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", from_host, prod_cnt, p32[0], p32[1], p32[2], p32[3], p32[4], p32[5]); } #endif // ENABLE_DMA_BUFFER_PACKET_DEBUG status = CyU3PDmaChannelCommitBuffer (chHandle, input->buffer_p.count, 0); @@ -594,7 +618,7 @@ void dma_callback ( LOCKP(lock); cnt->ABORTED++; UNLOCKP(lock); - + msg("! Aborted %i", from_host); } else if (type == CY_U3P_DMA_CB_ERROR) @@ -602,7 +626,7 @@ void dma_callback ( LOCKP(lock); cnt->ERROR++; UNLOCKP(lock); - + msg("! Error %i", from_host); } else if (type == CY_U3P_DMA_CB_PROD_SUSP) @@ -610,7 +634,7 @@ void dma_callback ( LOCKP(lock); cnt->PROD_SUSP++; UNLOCKP(lock); - + msg("! Prod suspend %i", from_host); } else if (type == CY_U3P_DMA_CB_CONS_SUSP) @@ -618,8 +642,10 @@ void dma_callback ( LOCKP(lock); cnt->CONS_SUSP++; UNLOCKP(lock); - - msg("! Cons suspend %i", from_host); + + //msg("! Cons suspend %i", from_host); + + CyU3PDmaChannelResume (chHandle, CyFalse, CyTrue); } } @@ -672,7 +698,7 @@ void gpio_interrupt_callback(uint8_t gpio_id) { * everything will come back up properly. */ void b200_fw_stop(void) { msg("b200_fw_stop"); - + CyU3PEpConfig_t usb_endpoint_config; /* Update the flag. */ @@ -683,14 +709,14 @@ void b200_fw_stop(void) { CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); - + /* Reset the DMA channels */ // SDK 1.3 known issue #1 - probably not necessary since Destroy is next, but just in case CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); CyU3PDmaChannelReset(&ctrl_cons_to_prod_chan_handle); CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); - + /* Destroy the DMA channels */ CyU3PDmaChannelDestroy(&data_cons_to_prod_chan_handle); CyU3PDmaChannelDestroy(&data_prod_to_cons_chan_handle); @@ -716,7 +742,7 @@ void reset_gpif(void) { CyU3PGpioSetValue(GPIO_FPGA_RESET, CyTrue); // Bring down GPIF - CyU3PGpifDisable(CyTrue); + CyU3PGpifDisable(/*CyTrue*/CyFalse); /* Reset the DMA channels */ CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); @@ -725,42 +751,41 @@ void reset_gpif(void) { CyU3PDmaChannelReset(&ctrl_prod_to_cons_chan_handle); /* Reset the DMA transfers */ - CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, \ - DMA_SIZE_INFINITE); - - CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, \ - DMA_SIZE_INFINITE); - - CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, \ - DMA_SIZE_INFINITE); - - CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, \ - DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); /* Flush the USB endpoints */ CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); CyU3PUsbFlushEp(CTRL_ENDPOINT_PRODUCER); CyU3PUsbFlushEp(CTRL_ENDPOINT_CONSUMER); - + /* Load the GPIF configuration for Slave FIFO sync mode. */ - CyU3PGpifLoad(&CyFxGpifConfig); - + //CyU3PGpifLoad(&CyFxGpifConfig); + /* Start the state machine. */ - CyU3PGpifSMStart(RESET, ALPHA_RESET); - + //if (CyU3PGpifSMStart(RESET, ALPHA_RESET) != CY_U3P_SUCCESS) + // msg("! CyU3PGpifSMStart"); + /* Configure the watermarks for the slfifo-write buffers. */ - CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1); - CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1); - CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1); - CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1); - + //CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1); + //CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1); + //CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1); + //CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1); + CyU3PGpioSetValue(GPIO_FPGA_RESET, CyFalse); - + CyU3PThreadSleep(FPGA_RESET_SETTLING_TIME); - + + if (CyU3PGpifSMStart(RESET, ALPHA_RESET) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSMStart"); + + msg("GPIF reset"); + b200_start_fpga_sb_gpio(); - + g_fx3_state = STATE_RUNNING; } @@ -792,11 +817,11 @@ CyU3PReturnStatus_t b200_set_io_matrix(CyBool_t fpga_config_mode) { io_config_matrix.useI2C = CyTrue; io_config_matrix.useI2S = CyFalse; io_config_matrix.useSpi = fpga_config_mode; - + res = CyU3PDeviceConfigureIOMatrix(&io_config_matrix); if (res != CY_U3P_SUCCESS) msg("! ConfigureIOMatrix"); - + return res; } @@ -814,11 +839,11 @@ CyU3PReturnStatus_t b200_gpio_init(CyBool_t set_callback) { gpio_clock_config.simpleDiv = CY_U3P_GPIO_SIMPLE_DIV_BY_2; gpio_clock_config.clkSrc = CY_U3P_SYS_CLK; gpio_clock_config.halfDiv = 0; - + res = CyU3PGpioInit(&gpio_clock_config, (set_callback ? gpio_interrupt_callback : NULL)); if (res != CY_U3P_SUCCESS) msg("! CyU3PGpioInit"); - + return res; } @@ -827,36 +852,36 @@ void sb_write(uint8_t reg, uint32_t val) { #ifdef ENABLE_FPGA_SB const int len = 32; int i; - + if (g_fpga_sb_enabled == CyFalse) return; - + reg += FPGA_SB_UART_ADDR_BASE; - + //CyU3PBusyWait(1); // Can be used after each SetValue to slow down bit changes - + // START CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // Should already be 1 CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 0); - + // ADDR[8] for (i = 7; i >= 0; i--) { uint8_t bit = ((reg & (0x1 << i)) ? 0x01 : 0x00); CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, bit); - + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // FPGA reads bit } - + // DATA[32] for (i = (len-1); i >= 0; i--) { uint8_t bit = ((val & (0x1 << i)) ? 0x01 : 0x00); CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, bit); - + CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); // FPGA reads bit } - + // STOP CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 0); CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 0); @@ -888,10 +913,10 @@ void b200_enable_fpga_sb_gpio(CyBool_t enable) { #ifdef ENABLE_FPGA_SB CyU3PGpioSimpleConfig_t gpio_config; CyU3PReturnStatus_t res; - + if (enable == CyFalse) { g_fpga_sb_enabled = CyFalse; - + return; } @@ -900,7 +925,7 @@ void b200_enable_fpga_sb_gpio(CyBool_t enable) { gpio_config.driveHighEn = CyTrue; gpio_config.inputEn = CyFalse; gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - + res = CyU3PGpioSetSimpleConfig(GPIO_FPGA_SB_SCL, &gpio_config); if (res != CY_U3P_SUCCESS) { msg("! GpioSetSimpleConfig GPIO_FPGA_SB_SCL"); @@ -912,9 +937,9 @@ void b200_enable_fpga_sb_gpio(CyBool_t enable) { CyU3PGpioSetValue(GPIO_FPGA_SB_SCL, 1); CyU3PGpioSetValue(GPIO_FPGA_SB_SDA, 1); - + g_fpga_sb_enabled = CyTrue; - + msg("Debug SB OK"); #endif // ENABLE_FPGA_SB } @@ -923,10 +948,10 @@ void b200_enable_fpga_sb_gpio(CyBool_t enable) { void b200_start_fpga_sb_gpio(void) { #ifdef ENABLE_FPGA_SB LOCK(g_suart_lock); - sb_write(SUART_CLKDIV, g_fpga_sb_uart_div); // 16-bit reg, master clock = 100 MHz (434*2x = 230400/2) + sb_write(SUART_CLKDIV, /*g_fpga_sb_uart_div*/g_config.sb_baud_div); // 16-bit reg, master clock = 100 MHz (434*2x = 230400/2) _sb_write_string("\r\n B2x0 FPGA reset\r\n"); UNLOCK(g_suart_lock); - + msg("Compat: %d.%d", FX3_COMPAT_MAJOR, FX3_COMPAT_MINOR); msg("FX3 SDK: %d.%d.%d (build %d)", CYFX_VERSION_MAJOR, CYFX_VERSION_MINOR, CYFX_VERSION_PATCH, CYFX_VERSION_BUILD); #endif // ENABLE_FPGA_SB @@ -940,15 +965,15 @@ void b200_start_fpga_sb_gpio(void) { * application thread will re-configure some of the pins. */ void b200_gpios_pre_fpga_config(void) { CyU3PGpioSimpleConfig_t gpio_config; - + //b200_enable_fpga_sb_gpio(CyFalse); - + //CyU3PGpioDeInit(); - + b200_set_io_matrix(CyTrue); - + //b200_gpio_init(CyTrue); // This now done once during startup - + //////////////////////////////////// /* GPIO[0:32] must be set with the DeviceOverride function, instead of the @@ -989,24 +1014,24 @@ void b200_gpios_pre_fpga_config(void) { /* Initialize GPIO output values. */ CyU3PGpioSetValue(GPIO_FPGA_RESET, 0); CyU3PGpioSetValue(GPIO_PROGRAM_B, 1); - + b200_enable_fpga_sb_gpio(CyTrue); // So SCL/SDA are already high when SB state machine activates } void b200_slfifo_mode_gpio_config(void) { CyU3PGpioSimpleConfig_t gpio_config; - + //b200_enable_fpga_sb_gpio(CyFalse); - + //CyU3PGpioDeInit(); - + b200_set_io_matrix(CyFalse); //b200_gpio_init(CyFalse); // This now done once during startup - + //////////////////////////////////// - + /* GPIO[0:32] must be set with the DeviceOverride function, instead of the * SimpleEn array configuration. */ CyU3PDeviceGpioOverride(GPIO_FPGA_RESET, CyTrue); @@ -1015,7 +1040,7 @@ void b200_slfifo_mode_gpio_config(void) { CyU3PDeviceGpioOverride(GPIO_FX3_CE, CyTrue); CyU3PDeviceGpioOverride(GPIO_FX3_MISO, CyTrue); CyU3PDeviceGpioOverride(GPIO_FX3_MOSI, CyTrue); - + /* Configure GPIOs: * Outputs: * driveLowEn = True @@ -1031,13 +1056,13 @@ void b200_slfifo_mode_gpio_config(void) { gpio_config.driveHighEn = CyTrue; gpio_config.inputEn = CyFalse; gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - + CyU3PGpioSetSimpleConfig(GPIO_FPGA_RESET, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_SHDN_SW, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_FX3_SCLK, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_FX3_CE, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_FX3_MOSI, &gpio_config); - + /* Reconfigure the GPIO configure struct for inputs that do NOT require * interrupts attached to them. */ gpio_config.outValue = CyFalse; @@ -1045,23 +1070,23 @@ void b200_slfifo_mode_gpio_config(void) { gpio_config.driveLowEn = CyFalse; gpio_config.driveHighEn = CyFalse; gpio_config.intrMode = CY_U3P_GPIO_NO_INTR; - + CyU3PGpioSetSimpleConfig(GPIO_FX3_MISO, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_AUX_PWR_ON, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_PROGRAM_B, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_INIT_B, &gpio_config); CyU3PGpioSetSimpleConfig(GPIO_DONE, &gpio_config); - + /* Initialize GPIO output values. */ CyU3PGpioSetValue(GPIO_FPGA_RESET, 0); CyU3PGpioSetValue(GPIO_SHDN_SW, 1); CyU3PGpioSetValue(GPIO_FX3_SCLK, 0); CyU3PGpioSetValue(GPIO_FX3_CE, 1); CyU3PGpioSetValue(GPIO_FX3_MOSI, 0); - + // Disabled here as only useful once FPGA has been programmed //b200_enable_fpga_sb_gpio(CyTrue); - //b200_start_fpga_sb_gpio(); // Set set up SB USART + //b200_start_fpga_sb_gpio(); // Set up SB USART } @@ -1072,7 +1097,7 @@ void b200_slfifo_mode_gpio_config(void) { * ready to receive data from the host. */ void b200_fw_start(void) { msg("b200_fw_start"); - + CyU3PDmaChannelConfig_t dma_channel_config; CyU3PEpConfig_t usb_endpoint_config; CyU3PUSBSpeed_t usb_speed; @@ -1095,9 +1120,9 @@ void b200_fw_start(void) { data_buffer_size = 512; g_vendor_req_buff_size = USB2_VREQ_BUF_SIZE; // Max 64 num_packets_per_burst = USB2_PACKETS_PER_BURST; // 1 - + data_buffer_size_to_host = data_buffer_size_from_host = data_buffer_size; - + break; case CY_U3P_SUPER_SPEED: @@ -1110,41 +1135,49 @@ void b200_fw_start(void) { msg("LPMDisable OK"); //#endif // PREVENT_LOW_POWER_MODE max_packet_size = 1024; // Per USB3 spec - + // SDK ver: total available buffer memory // 1.2.3: 204KB // 1.3.1: 188KB - + // These options should be ignored - data_buffer_count *MUST* be 1 // They follow is kept for future testing - + // 1K //data_buffer_count = 64; //data_buffer_size = 1024; - + // 4K //data_buffer_count = 8; //data_buffer_size = 4096; - + + // 8K + //data_buffer_count = 4; + //data_buffer_size = 4096*2; + // 16K //data_buffer_count = 2*2; //data_buffer_size = 16384; // Default 16K - + // 32K //data_buffer_count = 2; //data_buffer_size = 16384*2; - - data_buffer_count = 1; - data_buffer_size = ((1 << 16) - 1); - data_buffer_size -= (data_buffer_size % 1024); // Align to 1K boundary - + + //data_buffer_count = 1; + //data_buffer_size = ((1 << 16) - 1); + //data_buffer_size = 16384; + //data_buffer_size -= (data_buffer_size % 1024); // Align to 1K boundary + + data_buffer_count = g_config.dma_buffer_count; + data_buffer_size = g_config.dma_buffer_size; + data_buffer_size_to_host = data_buffer_size; data_buffer_size_from_host = data_buffer_size; - + g_vendor_req_buff_size = USB3_VREQ_BUF_SIZE; // Max 512 - num_packets_per_burst = USB3_PACKETS_PER_BURST; // 16 + num_packets_per_burst = USB3_PACKETS_PER_BURST*1+4*0; // 16 break; - + case CY_U3P_NOT_CONNECTED: msg("! CY_U3P_NOT_CONNECTED"); return; @@ -1152,9 +1185,31 @@ void b200_fw_start(void) { default: return; } - + msg("[DMA] to host: %d, from host: %d, depth: %d, burst size: %d", data_buffer_size_to_host, data_buffer_size_from_host, data_buffer_count, num_packets_per_burst); +#ifdef ENABLE_MANUAL_DMA_XFER + msg("[DMA] Callback enabled"); + +#ifdef ENABLE_P2U_SUSP_EOP + msg("[DMA] P2U_SUSP_EOP enabled"); +#endif // ENABLE_P2U_SUSP_EOP +#ifdef ENABLE_MANUAL_DMA_XFER_FROM_HOST + msg("[DMA] Manual transfers from host"); +#endif // ENABLE_MANUAL_DMA_XFER_FROM_HOST +#ifdef ENABLE_MANUAL_DMA_XFER_TO_HOST + msg("[DMA] Manual transfers to host"); +#endif // ENABLE_MANUAL_DMA_XFER_TO_HOST +#ifdef ENABLE_DMA_BUFFER_PACKET_DEBUG + msg("[DMA] Packet debugging enabled"); +#endif // ENABLE_DMA_BUFFER_PACKET_DEBUG + +#else + msg("[DMA] AUTO transfer mode"); +#endif // ENABLE_MANUAL_DMA_XFER + + msg("[DMA] Transfer override: %s", (g_config.manual_dma ? "manual" : "auto")); + /************************************************************************* * Slave FIFO Data DMA Channel Configuration *************************************************************************/ @@ -1205,6 +1260,8 @@ CY_U3P_DMA_CB_PROD_SUSP | CY_U3P_DMA_CB_CONS_SUSP | #endif // ENABLE_MANUAL_DMA_XFER 0; + //if (g_config.manual_dma == 0) + // dma_channel_config.notification = 0; // Force all off is manual is disabled dma_channel_config.cb = #if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) from_host_dma_callback; @@ -1218,16 +1275,16 @@ CY_U3P_DMA_CB_CONS_SUSP | CyU3PDmaChannelCreate (&data_cons_to_prod_chan_handle, #if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_FROM_HOST) - /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL, + (g_config.manual_dma ? /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL : CY_U3P_DMA_TYPE_AUTO), #else CY_U3P_DMA_TYPE_AUTO, #endif // ENABLE_MANUAL_DMA_XFER &dma_channel_config); - + // By default these will adopt 'usb_endpoint_config.pcktSize' //CyU3PSetEpPacketSize(DATA_ENDPOINT_PRODUCER, 16384); //CyU3PSetEpPacketSize(DATA_ENDPOINT_CONSUMER, 16384); - + /* Create a DMA AUTO channel for P2U transfer. */ dma_channel_config.size = data_buffer_size_to_host; dma_channel_config.prodSckId = DATA_RX_PPORT_SOCKET; @@ -1244,21 +1301,28 @@ CY_U3P_DMA_CB_ERROR | CY_U3P_DMA_CB_PROD_SUSP | CY_U3P_DMA_CB_CONS_SUSP | #endif // ENABLE_MANUAL_DMA_XFER +#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_P2U_SUSP_EOP) +CY_U3P_DMA_CB_CONS_SUSP | // For 'CyU3PDmaChannelSetSuspend' below +#endif // ENABLE_P2U_SUSP_EOP 0; + //if (g_config.manual_dma == 0) + // dma_channel_config.notification = 0; // Force all off is manual is disabled dma_channel_config.cb = -#if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) +#if defined(ENABLE_MANUAL_DMA_XFER) && (defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) || defined(ENABLE_P2U_SUSP_EOP)) to_host_dma_callback; #else NULL; #endif // ENABLE_MANUAL_DMA_XFER CyU3PDmaChannelCreate (&data_prod_to_cons_chan_handle, #if defined(ENABLE_MANUAL_DMA_XFER) && defined(ENABLE_MANUAL_DMA_XFER_TO_HOST) - /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL, + (g_config.manual_dma ? /*CY_U3P_DMA_TYPE_AUTO_SIGNAL*/CY_U3P_DMA_TYPE_MANUAL : CY_U3P_DMA_TYPE_AUTO), #else CY_U3P_DMA_TYPE_AUTO, #endif // ENABLE_MANUAL_DMA_XFER &dma_channel_config); - +#ifdef ENABLE_P2U_SUSP_EOP + CyU3PDmaChannelSetSuspend(&data_prod_to_cons_chan_handle, CY_U3P_DMA_SCK_SUSP_NONE, CY_U3P_DMA_SCK_SUSP_EOP); +#endif // ENABLE_P2U_SUSP_EOP /* Flush the Endpoint memory */ CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); @@ -1328,7 +1392,7 @@ CY_U3P_DMA_CB_CONS_SUSP | /* Set DMA channel transfer size. */ CyU3PDmaChannelSetXfer(&ctrl_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); CyU3PDmaChannelSetXfer(&ctrl_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - + //CyU3PUsbEnableEPPrefetch(); // To address USB_EVENT_EP_UNDERRUN on EP 0x86 (didn't fix it though) /* Update the application status flag. */ @@ -1364,76 +1428,76 @@ void event_usb_callback (CyU3PUsbEventType_t event_type, uint16_t event_data) { b200_fw_stop(); } break; - + case CY_U3P_USB_EVENT_CONNECT: msg("USB_EVENT_CONNECT"); break; - + case CY_U3P_USB_EVENT_SUSPEND: msg("USB_EVENT_SUSPEND"); break; - + case CY_U3P_USB_EVENT_RESUME: // Known issue: this is called repeatedly after a resume //msg("USB_EVENT_RESUME"); g_counters.resume_count++; // Not locked break; - + case CY_U3P_USB_EVENT_SPEED: msg("USB_EVENT_SPEED"); break; - + case CY_U3P_USB_EVENT_SETINTF: msg("USB_EVENT_SETINTF"); break; - + case CY_U3P_USB_EVENT_SET_SEL: msg("USB_EVENT_SET_SEL"); break; - + case CY_U3P_USB_EVENT_SOF_ITP: // CyU3PUsbEnableITPEvent //msg("USB_EVENT_SOF_ITP"); break; - + case CY_U3P_USB_EVENT_EP0_STAT_CPLT: //msg("USB_EVENT_EP0_STAT_CPLT"); // Occurs each time there's a control transfer break; - + case CY_U3P_USB_EVENT_VBUS_VALID: msg("USB_EVENT_VBUS_VALID"); break; - + case CY_U3P_USB_EVENT_VBUS_REMOVED: msg("USB_EVENT_VBUS_REMOVED"); break; - + case CY_U3P_USB_EVENT_HOST_CONNECT: msg("USB_EVENT_HOST_CONNECT"); break; - + case CY_U3P_USB_EVENT_HOST_DISCONNECT: msg("USB_EVENT_HOST_DISCONNECT"); break; - + case CY_U3P_USB_EVENT_OTG_CHANGE: msg("USB_EVENT_OTG_CHANGE"); break; - + case CY_U3P_USB_EVENT_OTG_VBUS_CHG: msg("USB_EVENT_OTG_VBUS_CHG"); break; - + case CY_U3P_USB_EVENT_OTG_SRP: msg("USB_EVENT_OTG_SRP"); break; - + case CY_U3P_USB_EVENT_EP_UNDERRUN: // See SDK 1.3 known issues 17 if this happens (can probably ignore first logged occurence) LOCK(g_counters_lock); ++g_counters.usb_ep_underrun_count; UNLOCK(g_counters_lock); - + msg("! USB_EVENT_EP_UNDERRUN on EP 0x%02x", event_data); break; - + case CY_U3P_USB_EVENT_LNK_RECOVERY: msg("USB_EVENT_LNK_RECOVERY"); break; @@ -1441,16 +1505,16 @@ void event_usb_callback (CyU3PUsbEventType_t event_type, uint16_t event_data) { case CY_U3P_USB_EVENT_USB3_LNKFAIL: msg("USB_EVENT_USB3_LNKFAIL"); break; - + case CY_U3P_USB_EVENT_SS_COMP_ENTRY: msg("USB_EVENT_SS_COMP_ENTRY"); break; - + case CY_U3P_USB_EVENT_SS_COMP_EXIT: msg("USB_EVENT_SS_COMP_EXIT"); break; #endif // (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) - + default: msg("! Unhandled USB event"); break; @@ -1510,7 +1574,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { if(wLength > b200_usb_product_desc[0]) { wLength = b200_usb_product_desc[0]; } - + //msg("MS string desc"); CyU3PUsbSendEP0Data(wLength, ((uint8_t *) b200_usb_product_desc)); @@ -1540,7 +1604,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { CyU3PUsbStall(wIndex, CyFalse, CyTrue); handled = CyTrue; CyU3PUsbAckSetup(); - + msg("Clear DATA_ENDPOINT_PRODUCER"); } @@ -1553,7 +1617,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { CyU3PUsbStall(wIndex, CyFalse, CyTrue); handled = CyTrue; CyU3PUsbAckSetup(); - + msg("Clear DATA_ENDPOINT_CONSUMER"); } @@ -1566,7 +1630,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { CyU3PUsbStall(wIndex, CyFalse, CyTrue); handled = CyTrue; CyU3PUsbAckSetup(); - + msg("Clear CTRL_ENDPOINT_PRODUCER"); } @@ -1579,7 +1643,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { CyU3PUsbStall(wIndex, CyFalse, CyTrue); handled = CyTrue; CyU3PUsbAckSetup(); - + msg("Clear CTRL_ENDPOINT_CONSUMER"); } } @@ -1595,7 +1659,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { switch(bRequest) { case B200_VREQ_BITSTREAM_START: { CyU3PUsbGetEP0Data(1, g_vendor_req_buffer, &read_count); - + g_fpga_programming_write_count = 0; CyU3PEventSet(&g_event_usb_config, EVENT_BITSTREAM_START, \ @@ -1614,12 +1678,12 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { } break; } - + case B200_VREQ_BITSTREAM_DATA_FILL: { CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &g_vendor_req_read_count); break; } - + case B200_VREQ_BITSTREAM_DATA_COMMIT: { /*CyU3PReturnStatus_t*/int spi_result = -1; if (g_fx3_state == STATE_CONFIGURING_FPGA) { @@ -1670,8 +1734,14 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { case B200_VREQ_GET_LOG: { LOCK(g_log_lock); - - if (log_buffer_idx == 0) + + if (log_buffer_len == 0) { + log_buffer[0] = '\0'; + CyU3PUsbSendEP0Data(1, (uint8_t*)log_buffer); + //CyU3PUsbSendEP0Data(0, NULL); + //CyU3PUsbAckSetup(); + } + else if (log_buffer_idx == 0) CyU3PUsbSendEP0Data(log_buffer_len, (uint8_t*)log_buffer); else { int len1 = min(LOG_BUFFER_SIZE - log_buffer_idx, log_buffer_len); @@ -1681,39 +1751,39 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { memcpy(log_contiguous_buffer + len1, log_buffer, log_buffer_len - len1); CyU3PUsbSendEP0Data(log_buffer_len, (uint8_t*)log_contiguous_buffer); } - + // FIXME: Necessary? Not used in the other ones //CyU3PUsbSendEP0Data(0, NULL); // Send ZLP since previous send has resulted in an integral # of packets - + log_reset(); - + UNLOCK(g_log_lock); - + //log_reset(); - + break; } case B200_VREQ_GET_COUNTERS: { LOCK(g_counters_lock); - + CyU3PUsbSendEP0Data(sizeof(COUNTERS), (uint8_t*)&g_counters); - + counters_auto_reset(); - + UNLOCK(g_counters_lock); - + //counters_auto_reset(); - + break; } - + case B200_VREQ_CLEAR_COUNTERS: { CyU3PUsbAckSetup(); //CyU3PUsbGetEP0Data(g_vendor_req_buff_size, g_vendor_req_buffer, &read_count); // Dummy - + counters_dma_reset(); - + break; } @@ -1750,14 +1820,14 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { //msg("USB event log [1] %i", (int)len); } } - + //if (len > 0) // Send a ZLP, otherwise it'll timeout CyU3PUsbSendEP0Data(len, g_usb_event_log_contiguous_buf); - + g_last_usb_event_log_index = idx; break; } - + case B200_VREQ_SET_CONFIG: { CyU3PUsbGetEP0Data(sizeof(CONFIG_MOD), (uint8_t*)g_vendor_req_buffer, &read_count); if (read_count == sizeof(CONFIG_MOD)) { @@ -1766,7 +1836,7 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { } break; } - + case B200_VREQ_GET_CONFIG: { CyU3PUsbSendEP0Data(sizeof(g_config), (uint8_t*)&g_config); break; @@ -1780,64 +1850,77 @@ CyBool_t usb_setup_callback(uint32_t data0, uint32_t data1) { for (i = 0; i < read_count; ++i) sb_write(SUART_TXCHAR, g_vendor_req_buffer[i]); UNLOCK(g_suart_lock); - + msg("Wrote %d SB chars", read_count); #else msg("SB is disabled"); #endif // ENABLE_FPGA_SB break; } - + case B200_VREQ_SET_SB_BAUD_DIV: { uint16_t div; CyU3PUsbGetEP0Data(sizeof(div), (uint8_t*)&div, &read_count); - + if (read_count == sizeof(div)) { #ifdef ENABLE_FPGA_SB LOCK(g_suart_lock); sb_write(SUART_CLKDIV, div); UNLOCK(g_suart_lock); msg("SUART_CLKDIV = %d", div); - g_fpga_sb_uart_div = div; // Store for GPIF (FPGA) reset + /*g_fpga_sb_uart_div*/g_config.sb_baud_div = div; // Store for GPIF (FPGA) reset #else msg("SB is disabled"); #endif // ENABLE_FPGA_SB } else msg("! SUART_CLKDIV received %d bytes", read_count); - + break; } - + case B200_VREQ_FLUSH_DATA_EPS: { //msg("Flushing data EPs..."); - - CyU3PUsbAckSetup(); - + + //CyU3PUsbAckSetup(); + + //CyU3PUsbResetEndpointMemories(); + // From host //CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); //CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); //CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); //CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); - + + //CyU3PDmaSocketDisable(DATA_RX_PPORT_SOCKET); + //CyU3PDmaChannelReset(&data_cons_to_prod_chan_handle); - CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); + if (CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle) != CY_U3P_SUCCESS) + { + msg("! CyU3PDmaChannelReset"); + } //CyU3PUsbFlushEp(DATA_ENDPOINT_PRODUCER); CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); //CyU3PUsbResetEp(DATA_ENDPOINT_PRODUCER); - CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); +// CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); + //CyU3PUsbStall(DATA_ENDPOINT_CONSUMER, CyFalse, CyTrue); //CyU3PDmaChannelSetXfer(&data_cons_to_prod_chan_handle, DMA_SIZE_INFINITE); + //CyU3PDmaSocketEnable(DATA_RX_PPORT_SOCKET); CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - + + //CyU3PUsbResetEndpointMemories(); + // To host //CyU3PDmaChannelReset(&data_prod_to_cons_chan_handle); //CyU3PUsbFlushEp(DATA_ENDPOINT_CONSUMER); //CyU3PUsbResetEp(DATA_ENDPOINT_CONSUMER); //CyU3PDmaChannelSetXfer(&data_prod_to_cons_chan_handle, DMA_SIZE_INFINITE); - + + CyU3PUsbAckSetup(); + break; } - + case B200_VREQ_EEPROM_WRITE: { i2cAddr = 0xA0 | ((wValue & 0x0007) << 1); CyU3PUsbGetEP0Data(((wLength + 15) & 0xFFF0), g_vendor_req_buffer, NULL); @@ -1941,6 +2024,97 @@ CyBool_t lpm_request_callback(CyU3PUsbLinkPowerMode link_mode) { } +/* Callback function to check for PIB ERROR*/ +void gpif_error_cb(CyU3PPibIntrType cbType, uint16_t cbArg) +{ + if (cbType==CYU3P_PIB_INTR_ERROR) + { + switch (CYU3P_GET_PIB_ERROR_TYPE(cbArg)) + { + case CYU3P_PIB_ERR_NONE: + break; + case CYU3P_PIB_ERR_THR0_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR0_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR1_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR1_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR2_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR2_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR3_WR_OVERRUN: + msg("CYU3P_PIB_ERR_THR3_WR_OVERRUN"); + break; + case CYU3P_PIB_ERR_THR0_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR0_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR1_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR1_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR2_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR2_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR3_RD_UNDERRUN: + msg("CYU3P_PIB_ERR_THR3_RD_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR0_ADAP_UNDERRUN: + msg("CYU3P_PIB_ERR_THR0_ADAP_UNDERRUN"); + break; + case CYU3P_PIB_ERR_THR1_ADAP_OVERRUN: + msg("CYU3P_PIB_ERR_THR1_ADAP_OVERRUN"); + break; + // FIXME: Other threads + case CYU3P_PIB_ERR_THR1_SCK_INACTIVE: + //msg("CYU3P_PIB_ERR_THR1_SCK_INACTIVE"); + ++g_counters.pib_counters[1].socket_inactive; // UNSYNC'd + break; + default: + msg("Unknown CYU3P_PIB_ERR %i", CYU3P_GET_PIB_ERROR_TYPE(cbArg)); + break; + } + + switch (CYU3P_GET_GPIF_ERROR_TYPE(cbArg)) + { + case CYU3P_GPIF_ERR_NONE: /**< No GPIF state machine errors. */ + //msg("CYU3P_GPIF_ERR_NONE"); + break; + case CYU3P_GPIF_ERR_INADDR_OVERWRITE: /**< Content of INGRESS_ADDR register is overwritten before read. */ + msg("CYU3P_GPIF_ERR_INADDR_OVERWRITE"); + break; + case CYU3P_GPIF_ERR_EGADDR_INVALID: /**< Attempt to read EGRESS_ADDR register before it is written to. */ + msg("CYU3P_GPIF_ERR_EGADDR_INVALID"); + break; + case CYU3P_GPIF_ERR_DATA_READ_ERR: /**< Read from DMA data thread which is not ready. */ + msg("CYU3P_GPIF_ERR_DATA_READ_ERR"); + break; + case CYU3P_GPIF_ERR_DATA_WRITE_ERR: /**< Write to DMA data thread which is not ready. */ + msg("CYU3P_GPIF_ERR_DATA_WRITE_ERR"); + break; + case CYU3P_GPIF_ERR_ADDR_READ_ERR: /**< Read from DMA address thread which is not ready. */ + msg("CYU3P_GPIF_ERR_ADDR_READ_ERR"); + break; + case CYU3P_GPIF_ERR_ADDR_WRITE_ERR: /**< Write to DMA address thread which is not ready. */ + msg("CYU3P_GPIF_ERR_ADDR_WRITE_ERR"); + break; + case CYU3P_GPIF_ERR_INVALID_STATE: /**< GPIF state machine has reached an invalid state. */ + //msg("CYU3P_GPIF_ERR_INVALID_STATE"); + ++g_counters.invalid_gpif_state; // UNSYNC'd + break; + default: + msg("Unknown CYU3P_GPIF_ERR %i", CYU3P_GET_GPIF_ERROR_TYPE(cbArg)); + break; + } + } +} + + +void GpifStateChangeCb(uint8_t stateId) +{ + //msg("%d", stateId); + ++g_counters.state_transition_count; +} + + /*! Initialize and start the GPIF state machine. * * This function starts the GPIF Slave FIFO state machine on the FX3. Because on @@ -1948,7 +2122,7 @@ CyBool_t lpm_request_callback(CyU3PUsbLinkPowerMode link_mode) { * after FPGA configuration is complete. */ void b200_gpif_init(void) { msg("b200_gpif_init"); - + CyU3PPibClock_t pib_clock_config; /* Initialize the p-port block; disable DLL for sync GPIF. */ @@ -1956,19 +2130,34 @@ void b200_gpif_init(void) { pib_clock_config.clkSrc = CY_U3P_SYS_CLK; pib_clock_config.isHalfDiv = CyFalse; pib_clock_config.isDllEnable = CyFalse; - CyU3PPibInit(CyTrue, &pib_clock_config); + if (CyU3PPibInit(CyTrue, &pib_clock_config) != CY_U3P_SUCCESS) + msg("! CyU3PPibInit"); /* Load the GPIF configuration for Slave FIFO sync mode. */ - CyU3PGpifLoad(&CyFxGpifConfig); + if (CyU3PGpifLoad(&CyFxGpifConfig) != CY_U3P_SUCCESS) + msg("! CyU3PGpifLoad"); + + msg("GPIF loaded"); + + //CyU3PGpifRegisterSMIntrCallback(GpifStateChangeCb); /* Start the state machine. */ - CyU3PGpifSMStart(RESET, ALPHA_RESET); + //CyU3PGpifSMStart(RESET, ALPHA_RESET); /* Configure the watermarks for the slfifo-write buffers. */ - CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1); - CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1); - CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1); - CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1); + if (CyU3PGpifSocketConfigure(0, DATA_TX_PPORT_SOCKET, 5, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 0"); + if (CyU3PGpifSocketConfigure(1, DATA_RX_PPORT_SOCKET, 6, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 1"); + if (CyU3PGpifSocketConfigure(2, CTRL_COMM_PPORT_SOCKET, 5, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 2"); + if (CyU3PGpifSocketConfigure(3, CTRL_RESP_PPORT_SOCKET, 6, CyFalse, 1) != CY_U3P_SUCCESS) + msg("! CyU3PGpifSocketConfigure 3"); + + //CyU3PGpifSMStart(RESET, ALPHA_RESET); + + /* Register a callback for notification of PIB interrupts*/ + CyU3PPibRegisterCallback(gpif_error_cb, CYU3P_PIB_INTR_ERROR); } @@ -1979,7 +2168,7 @@ void b200_gpif_init(void) { * 32-bit mode. */ CyU3PReturnStatus_t b200_spi_init(void) { msg("b200_spi_init"); - + CyU3PSpiConfig_t spiConfig; /* Start the SPI module and configure the master. */ @@ -2000,10 +2189,10 @@ CyU3PReturnStatus_t b200_spi_init(void) { spiConfig.wordLen = 8; CyU3PReturnStatus_t res = CyU3PSpiSetConfig(&spiConfig, NULL); - + if (res != CY_U3P_SUCCESS) msg("! CyU3PSpiSetConfig"); - + return res; } @@ -2015,7 +2204,7 @@ CyU3PReturnStatus_t b200_spi_init(void) { */ void b200_usb_init(void) { //msg("b200_usb_init"); - + /* Initialize the I2C interface for the EEPROM of page size 64 bytes. */ CyFxI2cInit(CY_FX_USBI2C_I2C_PAGE_SIZE); @@ -2137,48 +2326,53 @@ void b200_usb_init(void) { CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 3, (uint8_t *) dev_serial); - + //////////////////////////////////////////////////////// // FIXME: CyU3PUsbSetTxDeemphasis(0x11); <0x1F // Shouldn't need to change this - uint32_t tx_swing = /*65*/45; // 65 & 45 are OK, 120 causes much link recovery. <128. 1.2V is USB3 limit. + const uint32_t tx_swing = g_config.tx_swing/*65*//*45*/; // 65 & 45 are OK, 120 causes much link recovery. <128. 1.2V is USB3 limit. if (CyU3PUsbSetTxSwing(tx_swing) == CY_U3P_SUCCESS) - msg("CyU3PUsbSetTxSwing %d", tx_swing); + msg("CyU3PUsbSetTxSwing: %d", tx_swing); else - msg("! CyU3PUsbSetTxSwing %d", tx_swing); + msg("! CyU3PUsbSetTxSwing: %d", tx_swing); //////////////////////////////////////////////////////// /* Connect the USB pins, and enable SuperSpeed (USB 3.0). */ - CyU3PConnectState(CyTrue, CyTrue); // connect, ssEnable + if (CyU3PConnectState(CyTrue, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { // connect, ssEnable + CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); + msg("Link up (speed: USB %d)", (int)usb_speed); // MAGIC: Values happen to map + } + else + msg("! Failed to establish link"); } void b200_restore_gpio_for_fpga_config(void) { CyU3PDeviceGpioRestore(GPIO_FPGA_RESET); CyU3PDeviceGpioRestore(GPIO_DONE); - + CyU3PDeviceGpioRestore(GPIO_FX3_SCLK); CyU3PDeviceGpioRestore(GPIO_FX3_CE); CyU3PDeviceGpioRestore(GPIO_FX3_MISO); CyU3PDeviceGpioRestore(GPIO_FX3_MOSI); - + //CyU3PGpioDeInit(); // Moved to just before init } void thread_fpga_config_entry(uint32_t input) { uint32_t event_flag; - + //msg("thread_fpga_config_entry"); - + for(;;) { - + // Event is set through VREQ if(CyU3PEventGet(&g_event_usb_config, \ (EVENT_FPGA_CONFIG), CYU3P_EVENT_AND_CLEAR, \ &event_flag, CYU3P_WAIT_FOREVER) == CY_U3P_SUCCESS) { - + //uint8_t old_state = g_fx3_state; uint32_t old_fpga_programming_write_count = 0; @@ -2200,7 +2394,7 @@ void thread_fpga_config_entry(uint32_t input) { /* Configure the device GPIOs for FPGA programming. */ b200_gpios_pre_fpga_config(); - + CyU3PSysWatchDogClear(); /* Initialize the SPI module that will be used for FPGA programming. */ @@ -2213,7 +2407,7 @@ void thread_fpga_config_entry(uint32_t input) { /* We can now begin configuring the FPGA. */ g_fx3_state = STATE_FPGA_READY; - + msg("Begin FPGA"); // Event is set through VREQ @@ -2232,7 +2426,7 @@ void thread_fpga_config_entry(uint32_t input) { CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); CyU3PSysWatchDogClear(); } - + if (wait_count >= FPGA_PROGRAMMING_BITSTREAM_START_POLL_COUNT) continue; @@ -2243,7 +2437,7 @@ void thread_fpga_config_entry(uint32_t input) { /* Wait for INIT_B to fall and rise. */ wait_count = 0; - + msg("Wait FPGA"); while(CyU3PEventGet(&g_event_usb_config, \ @@ -2282,9 +2476,9 @@ void thread_fpga_config_entry(uint32_t input) { /* We are ready to accept the FPGA bitstream! */ wait_count = 0; g_fx3_state = STATE_CONFIGURING_FPGA; - + msg("Configuring FPGA"); - + // g_fpga_programming_write_count is zero'd by VREQ triggering EVENT_BITSTREAM_START while(CyU3PEventGet(&g_event_usb_config, \ @@ -2308,7 +2502,7 @@ void thread_fpga_config_entry(uint32_t input) { wait_count = 0; old_fpga_programming_write_count = g_fpga_programming_write_count; } - + CyU3PThreadSleep(FPGA_PROGRAMMING_POLL_SLEEP); CyU3PSysWatchDogClear(); } @@ -2329,42 +2523,42 @@ void thread_fpga_config_entry(uint32_t input) { #endif // ENABLE_DONE_WORKAROUND if (wait_count >= FPGA_PROGRAMMING_DONE_POLL_COUNT) continue; - + msg("FPGA done"); - + /* Tell the host that we are ignoring it for a while. */ g_fx3_state = STATE_BUSY; - + CyU3PSysWatchDogClear(); - + /* Now that the FPGA is configured, we need to tear down the current SPI and * GPIO configs, and re-config for GPIF & bit-banged SPI operation. */ CyU3PSpiDeInit(); b200_restore_gpio_for_fpga_config(); - + CyU3PSysWatchDogClear(); - + /* Load the GPIO configuration for normal SLFIFO use. */ b200_slfifo_mode_gpio_config(); - + /* Tone down the drive strength on the P-port. */ //CyU3PSetPportDriveStrength(CY_U3P_DS_HALF_STRENGTH); - + CyU3PSysWatchDogClear(); - + /* FPGA configuration is complete! Time to get the GPIF state machine * running for Slave FIFO. */ b200_gpif_init(); - + CyU3PThreadSleep(1); b200_start_fpga_sb_gpio(); // Moved here to give SB time to init - + /* RUN, BABY, RUN! */ g_fx3_state = STATE_RUNNING; - + msg("Running"); } - + CyU3PThreadRelinquish(); } } @@ -2403,15 +2597,15 @@ void thread_main_app_entry(uint32_t input) { while((current_state >= CyU3PUsbLPM_U1) \ && (current_state <= CyU3PUsbLPM_U3)) { - + msg("! LPS = %i", current_state); CyU3PUsbSetLinkPowerState(CyU3PUsbLPM_U0); // This will wake up the host if it's trying to sleep CyU3PThreadSleep(1); - + if (CyU3PUsbGetSpeed () != CY_U3P_SUPER_SPEED) break; - + CyU3PUsbGetLinkPowerState (¤t_state); } } @@ -2426,12 +2620,12 @@ static uint32_t g_poll_last_phy_error_status = 0; void update_error_counters(void) { if (CyU3PUsbGetSpeed () != CY_U3P_SUPER_SPEED) return; - + uvint32_t reg = REG_LNK_PHY_ERROR_STATUS; uint32_t val = 0; if (CyU3PReadDeviceRegisters((uvint32_t*)reg, 1, &val) == CY_U3P_SUCCESS) { g_poll_last_phy_error_status |= (val & PHYERR_MASK); - + // Reset after read uint32_t zero = PHYERR_MASK; if (CyU3PWriteDeviceRegisters((uvint32_t*)reg, 1, &zero) != CY_U3P_SUCCESS) @@ -2441,12 +2635,12 @@ void update_error_counters(void) { // FIXME: Log once msg("! Reg read fail"); } - + // Equivalent code: //uint32_t* p = (uint32_t*)REG_LNK_PHY_ERROR_STATUS; //val = (*p); //(*p) = PHYERR_MASK; - + uint16_t phy_error_count = 0, link_error_count = 0; if (CyU3PUsbGetErrorCounts(&phy_error_count, &link_error_count) == CY_U3P_SUCCESS) { // Resets internal counters after call g_poll_last_phy_error_count += phy_error_count; @@ -2456,7 +2650,7 @@ void update_error_counters(void) { // FIXME: Log once msg("! CyU3PUsbGetErrorCounts"); } - + LOCK(g_counters_lock); g_counters.usb_error_update_count++; g_counters.usb_error_counters.phy_error_count += phy_error_count; @@ -2478,50 +2672,153 @@ void update_error_counters(void) { void thread_re_enum_entry(uint32_t input) { uint32_t event_flag; - + //msg("thread_re_enum_entry"); - + int keep_alive = 0; - + while (1) { if (CyU3PEventGet(&g_event_usb_config, \ (EVENT_RE_ENUM), CYU3P_EVENT_AND_CLEAR, \ &event_flag, RE_ENUM_THREAD_SLEEP_TIME) == CY_U3P_SUCCESS) { msg("Re-config"); - + // FIXME: This section is not finished - + // Not locking this since we only expect one write in VREQ and read afterward here - - int re_enum = g_config_mod.flags & (CF_RE_ENUM | CF_TX_SWING | CF_TX_DEEMPHASIS); - + + int re_enum = g_config_mod.flags & (CF_RE_ENUM | CF_TX_SWING | CF_TX_DEEMPHASIS | CF_DISABLE_USB2 | CF_ENABLE_AS_SUPERSPEED); + CyU3PThreadSleep(100); // Wait for EP0 xaction to complete - + //b200_fw_stop(); - + +/* + int tx_swing; // [90] [65] 45 + int tx_deemphasis; // 0x11 + int disable_usb2; // 0 + int enable_as_superspeed; // 1 + int pport_drive_strength; // CY_U3P_DS_THREE_QUARTER_STRENGTH + int dma_buffer_size; // [USB3] (max) + int dma_buffer_count; // [USB3] 1 + int manual_dma; // 0 + int sb_baud_div; // 434*2 +*/ + if (re_enum) { - msg("Link down"); - CyU3PConnectState(CyFalse, CyTrue); + if (CyU3PConnectState(CyFalse, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) + msg("Link down"); + else + msg("! Failed to bring link down"); } - + if (g_config_mod.flags & CF_TX_DEEMPHASIS) { - //g_config_mod.config.tx_deemphasis - //CyU3PUsbSetTxDeemphasis(0x11); <0x1F +#if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) + if ((g_config_mod.config.tx_deemphasis < 0x1F) && (CyU3PUsbSetTxDeemphasis(g_config_mod.config.tx_deemphasis) == CY_U3P_SUCCESS)) { + msg("TX deemphasis now: %d (was: %d)", g_config_mod.config.tx_deemphasis, g_config.tx_deemphasis); + g_config.tx_deemphasis = g_config_mod.config.tx_deemphasis; + } + else +#endif // #if (CYFX_VERSION_MAJOR >= 1) && (CYFX_VERSION_MINOR >= 3) + msg("! Failed to set TX deemphasis: %d (still: %d)", g_config_mod.config.tx_deemphasis, g_config.tx_deemphasis); } + if (g_config_mod.flags & CF_TX_SWING) { - //CyU3PUsbSetTxSwing(90); <128 + if ((g_config_mod.config.tx_swing < 128) && (CyU3PUsbSetTxSwing(g_config_mod.config.tx_swing) == CY_U3P_SUCCESS)) { + msg("TX swing now: %d (was: %d)", g_config_mod.config.tx_swing, g_config.tx_swing); + g_config.tx_swing = g_config_mod.config.tx_swing; + } + else + msg("! Failed to set TX swing: %d (still: %d)", g_config_mod.config.tx_swing, g_config.tx_swing); + } + + if (g_config_mod.flags & CF_DISABLE_USB2) { + if (CyU3PUsbControlUsb2Support((g_config_mod.config.disable_usb2 != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { + msg("USB 2 support now: %s (was: %d)", (g_config_mod.config.disable_usb2 ? "disabled" : "enabled"), (g_config.disable_usb2 ? "disabled" : "enabled")); + g_config.disable_usb2 = g_config_mod.config.disable_usb2; + } + else + msg("! Failed to change USB 2 support to: %s (still: %s)", (g_config_mod.config.disable_usb2 ? "enabled" : "disabled"), (g_config.disable_usb2 ? "enabled" : "disabled")); + } + + if (g_config_mod.flags & CF_PPORT_DRIVE_STRENGTH) { + // CY_U3P_DS_QUARTER_STRENGTH,CY_U3P_DS_HALF_STRENGTH,CY_U3P_DS_THREE_QUARTER_STRENGTH,CY_U3P_DS_FULL_STRENGTH + if ((g_config_mod.config.pport_drive_strength >= CY_U3P_DS_QUARTER_STRENGTH) && + (g_config_mod.config.pport_drive_strength <= CY_U3P_DS_FULL_STRENGTH) && + (CyU3PSetPportDriveStrength(g_config_mod.config.pport_drive_strength) == CY_U3P_SUCCESS)) { + msg("PPort drive strength now: %d (was: %d)", g_config_mod.config.pport_drive_strength, g_config.pport_drive_strength); + g_config.pport_drive_strength = g_config_mod.config.pport_drive_strength; + } + else + msg("! Failed to set PPort drive strength: %d (still: %d)", g_config_mod.config.pport_drive_strength, g_config.pport_drive_strength); + } + + int reinit_dma = g_config_mod.flags & (CF_MANUAL_DMA | CF_DMA_BUFFER_COUNT | CF_DMA_BUFFER_SIZE); + if (re_enum) + reinit_dma = 0; // Don't need to if re-enumerating + + if (g_config_mod.flags & CF_MANUAL_DMA) { +#ifdef ENABLE_MANUAL_DMA_XFER + msg("DMA transfers will be: %s (was: %s)", (g_config_mod.config.manual_dma ? "manual" : "auto"), (g_config.manual_dma ? "manual" : "auto")); + g_config.manual_dma = g_config_mod.config.manual_dma; +#else + msg("! Manual DMA transfers not compiled into FW"); +#endif // ENABLE_MANUAL_DMA_XFER + } + + if (g_config_mod.flags & CF_DMA_BUFFER_COUNT) { + msg("DMA buffer count will be: %d (was: %d)", g_config_mod.config.dma_buffer_count, g_config.dma_buffer_count); + g_config.dma_buffer_count = g_config_mod.config.dma_buffer_count; + } + + if (g_config_mod.flags & CF_DMA_BUFFER_SIZE) { + msg("DMA buffer size will be: %d (was: %d)", g_config_mod.config.dma_buffer_size, g_config.dma_buffer_size); + g_config.dma_buffer_size = g_config_mod.config.dma_buffer_size; + } + + if (g_config_mod.flags & CF_SB_BAUD_DIV) { +#ifdef ENABLE_FPGA_SB + LOCK(g_suart_lock); + sb_write(SUART_CLKDIV, g_config_mod.config.sb_baud_div); + UNLOCK(g_suart_lock); + msg("SUART_CLKDIV now: %d (was: %d)", g_config_mod.config.sb_baud_div, g_config.sb_baud_div); + g_config.sb_baud_div = g_config_mod.config.sb_baud_div; +#else + msg("! Failed to set SUART_CLKDIV: SB is disabled (still: %d)", g_config.sb_baud_div); +#endif // ENABLE_FPGA_SB } - //CyU3PUsbControlUsb2Support(); - //b200_fw_start() + if (g_config_mod.flags & CF_ENABLE_AS_SUPERSPEED) { + msg("Enable SuperSpeed: %s (was: %s)", (g_config_mod.config.enable_as_superspeed ? "yes" : "no"), (g_config.enable_as_superspeed ? "yes" : "no")); + g_config.enable_as_superspeed = g_config_mod.config.enable_as_superspeed; + } + + if (reinit_dma) { + if (g_app_running) { + msg("Stopping FW..."); + + b200_fw_stop(); + } + + msg("Starting FW..."); + + b200_fw_start(); + } + else // Shouldn't be re-init'ing AND re-enum'ing /* Connect the USB pins, and enable SuperSpeed (USB 3.0). */ if (re_enum) { - msg("Link up"); - CyU3PConnectState(CyTrue, CyTrue); // CHECK: Assuming all other important state will persist + msg("Connecting... (as SuperSpeed: %d)", g_config.enable_as_superspeed); + + if (CyU3PConnectState(CyTrue, (g_config.enable_as_superspeed != 0 ? CyTrue : CyFalse)) == CY_U3P_SUCCESS) { // CHECK: Assuming all other important state will persist + CyU3PUSBSpeed_t usb_speed = CyU3PUsbGetSpeed(); + msg("Link up (speed: USB %d)", (int)usb_speed); // MAGIC: Values happen to map + } + else + msg("! Failed to bring link up"); } - + counters_reset_usb_errors(); } else { @@ -2533,7 +2830,7 @@ void thread_re_enum_entry(uint32_t input) { update_error_counters(); #endif // !ENABLE_FPGA_SB } - + CyU3PThreadRelinquish(); } } @@ -2548,26 +2845,26 @@ void base16_encode(uint8_t v, char out[2], char first) { #ifdef ENABLE_FPGA_SB void thread_fpga_sb_poll_entry(uint32_t input) { //msg("thread_fpga_sb_poll_entry"); - + while (1) { uint16_t i; uint8_t has_change = 0; - + update_error_counters(); - + /*if (g_poll_last_phy_error_count > 0) has_change = 1; if (g_poll_last_link_error_count > 0) has_change = 1;*/ if (g_poll_last_phy_error_status != 0) has_change = 1; - + uint16_t idx = CyU3PUsbGetEventLogIndex(); // Current *write* pointer if (idx > (USB_EVENT_LOG_SIZE-1)) { msg("! USB event log idx = %i", (int)idx); break; } - + uint8_t has_usb_events = 0; // Assuming logging won't wrap around between get calls (i.e. buffer should be long enough) if (g_fpga_sb_last_usb_event_log_index != idx) { @@ -2578,7 +2875,7 @@ void thread_fpga_sb_poll_entry(uint32_t input) { break; } } - + if (has_usb_events == 0) { for (i = 0; i < idx; i++) { if (g_usb_event_log[i] != 0x14 && g_usb_event_log[i] != 0x15 && g_usb_event_log[i] != 0x16) { // CTRL, STATUS, ACKSETUP @@ -2597,15 +2894,15 @@ void thread_fpga_sb_poll_entry(uint32_t input) { } } } - + if (has_change || has_usb_events) { LOCK(g_suart_lock); - + sb_write(SUART_TXCHAR, UPT_USB_EVENTS); - + char out[3]; out[2] = '\0'; - + if (has_usb_events) { if (idx < g_fpga_sb_last_usb_event_log_index) { for (i = g_fpga_sb_last_usb_event_log_index; i < USB_EVENT_LOG_SIZE; i++) { @@ -2614,7 +2911,7 @@ void thread_fpga_sb_poll_entry(uint32_t input) { base16_encode(g_usb_event_log[i], out, 'A'); _sb_write_string(out); } - + for (i = 0; i < idx; i++) { if (g_usb_event_log[i] == 0x14 || g_usb_event_log[i] == 0x15 || g_usb_event_log[i] == 0x16) // CTRL, STATUS, ACKSETUP continue; @@ -2631,10 +2928,10 @@ void thread_fpga_sb_poll_entry(uint32_t input) { } } } - + // USB events: A-P,A-P // PHY error status: a,a-i - + if (g_poll_last_phy_error_status != 0) { uint32_t mask; size_t offset; @@ -2645,32 +2942,32 @@ void thread_fpga_sb_poll_entry(uint32_t input) { } } } - + /*char buf[6]; - + if (g_poll_last_phy_error_count > 0) { sb_write(SUART_TXCHAR, 'b'); snprintf(buf, sizeof(buf)-1, "%d", g_poll_last_phy_error_count); _sb_write_string(buf); } - + if (g_poll_last_link_error_count > 0) { sb_write(SUART_TXCHAR, 'c'); snprintf(buf, sizeof(buf)-1, "%d", g_poll_last_link_error_count); _sb_write_string(buf); }*/ - + _sb_write_string("\r\n"); - + UNLOCK(g_suart_lock); } - + g_poll_last_phy_error_count = 0; g_poll_last_link_error_count = 0; g_poll_last_phy_error_status = 0; - + g_fpga_sb_last_usb_event_log_index = idx; - + CyU3PThreadRelinquish(); } } @@ -2692,10 +2989,10 @@ void CyFxApplicationDefine(void) { #ifdef ENABLE_FPGA_SB void *fpga_sb_poll_thread_ptr; #endif // ENABLE_FPGA_SB - + g_counters.magic = COUNTER_MAGIC; - memset(&g_config, 0xFF, sizeof(g_config)); // Initialise to -1 - + //memset(&g_config, 0xFF, sizeof(g_config)); // Initialise to -1 + CyU3PMutexCreate(&g_log_lock, CYU3P_NO_INHERIT); CyU3PMutexCreate(&g_counters_lock, CYU3P_NO_INHERIT); CyU3PMutexCreate(&g_counters_dma_from_host_lock, CYU3P_NO_INHERIT); @@ -2706,36 +3003,37 @@ void CyFxApplicationDefine(void) { #ifdef ENABLE_USB_EVENT_LOGGING CyU3PUsbInitEventLog(g_usb_event_log, USB_EVENT_LOG_SIZE); #endif // ENABLE_USB_EVENT_LOGGING - + //////////////////////////////////////////////////////// - + /* Tell the host that we are ignoring it for a while. */ g_fx3_state = STATE_BUSY; - + /* Set the FX3 compatibility number. */ compat_num[0] = FX3_COMPAT_MAJOR; compat_num[1] = FX3_COMPAT_MINOR; - + /* Initialize the USB system. */ b200_usb_init(); - + /* Turn on the Watchdog Timer. */ CyU3PSysWatchDogConfigure(CyTrue, WATCHDOG_TIMEOUT); - + /* Go do something. Probably not useful, because you aren't configured. */ g_fx3_state = STATE_UNCONFIGURED; - + //////////////////////////////////////////////////////// - + b200_gpio_init(CyTrue); - + b200_enable_fpga_sb_gpio(CyTrue); - + msg("Compat: %d.%d", FX3_COMPAT_MAJOR, FX3_COMPAT_MINOR); msg("FX3 SDK: %d.%d.%d (build %d)", CYFX_VERSION_MAJOR, CYFX_VERSION_MINOR, CYFX_VERSION_PATCH, CYFX_VERSION_BUILD); - + msg("FW built: %s %s", __TIME__, __DATE__); + //////////////////////////////////////////////////////// - + /* Create the USB event group that we will use to track USB events from the * application thread. */ CyU3PEventCreate(&g_event_usb_config); @@ -2838,14 +3136,14 @@ int main(void) { status = CyU3PDeviceCacheControl(CyTrue, CyFalse, CyFalse); // Icache, Dcache, DMAcache if (status != CY_U3P_SUCCESS) goto handle_fatal_error; - + /* Configure the IO peripherals on the FX3. The gpioSimpleEn arrays are * bitmaps, where each bit represents the GPIO of the matching index - the * second array is index + 32. */ status = b200_set_io_matrix(CyTrue); if(status != CY_U3P_SUCCESS) goto handle_fatal_error; - + /* This function calls starts the RTOS kernel. * * ABANDON ALL HOPE, YE WHO ENTER HERE */ diff --git a/firmware/fx3/b200/b200_main.h b/firmware/fx3/b200/b200_main.h index 61048abc9..9fe8b9511 100644 --- a/firmware/fx3/b200/b200_main.h +++ b/firmware/fx3/b200/b200_main.h @@ -10,7 +10,7 @@ #include "cyu3types.h" #include "cyu3usbconst.h" -#define FX3_COMPAT_MAJOR (uint8_t)(7) +#define FX3_COMPAT_MAJOR (uint8_t)(8) #define FX3_COMPAT_MINOR (uint8_t)(0) /* GPIO Pins */ diff --git a/firmware/fx3/b200/b200_usb_descriptors.c b/firmware/fx3/b200/b200_usb_descriptors.c index 03dbce74a..53979219b 100644 --- a/firmware/fx3/b200/b200_usb_descriptors.c +++ b/firmware/fx3/b200/b200_usb_descriptors.c @@ -1,5 +1,5 @@ // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 2013-2015 Ettus Research LLC // /* Define the USB 2.0 and USB 3.0 enumeration descriptions for the USRP B200 @@ -303,7 +303,7 @@ const uint8_t b200_usb_ss_config_desc[] __attribute__ ((aligned (32))) = 0x6A,0x00, /* Length of this descriptor and all sub descriptors */ 0x05, /* Number of interfaces */ 0x01, /* Configuration number */ - 0x00, /* COnfiguration string index */ + 0x00, /* Configuration string index */ 0x80, /* Config characteristics - D6: Self power; D5: Remote wakeup */ 0x01, /* Lie about the max power consumption (in 8mA unit) : 8mA */ @@ -424,6 +424,102 @@ const uint8_t b200_usb_ss_config_desc[] __attribute__ ((aligned (32))) = }; +const uint8_t b200_usb_ss_config_desc_new[] __attribute__ ((aligned (32))) = +{ + /* Configuration descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_CONFIG_DESCR, /* Configuration descriptor type */ + 0x4F,0x00, /* Length of this descriptor and all sub descriptors */ + 0x02, /* Number of interfaces */ + 0x01, /* Configuration number */ + 0x00, /* COnfiguration string index */ + 0x80, /* Config characteristics - D6: Self power; D5: Remote wakeup */ + 0x01, /* Lie about the max power consumption (in 8mA unit) : 8mA */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x00, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x00, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Interface descriptor */ + 0x09, /* Descriptor size */ + CY_U3P_USB_INTRFC_DESCR, /* Interface Descriptor type */ + 0x01, /* Interface number */ + 0x00, /* Alternate setting number */ + 0x04, /* Number of end points */ + 0xFF, /* Interface class */ + 0x00, /* Interface sub class */ + 0x00, /* Interface protocol code */ + 0x02, /* Interface descriptor string index */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Super speed endpoint companion descriptor for producer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00, /* Service interval for the EP : 0 for bulk */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + DATA_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for Bulk */ + + /* Super speed endpoint companion descriptor for consumer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00, /* Service interval for the EP : 0 for bulk */ + + /* Endpoint descriptor for producer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_PRODUCER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for bulk */ + + /* Super speed endpoint companion descriptor for producer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00, /* Service interval for the EP : 0 for bulk */ + + /* Endpoint descriptor for consumer EP */ + 0x07, /* Descriptor size */ + CY_U3P_USB_ENDPNT_DESCR, /* Endpoint descriptor type */ + CTRL_ENDPOINT_CONSUMER, /* Endpoint address and description */ + CY_U3P_USB_EP_BULK, /* Bulk endpoint type */ + 0x00,0x04, /* Max packet size = 1024 bytes */ + 0x00, /* Servicing interval for data transfers : 0 for Bulk */ + + /* Super speed endpoint companion descriptor for consumer EP */ + 0x06, /* Descriptor size */ + CY_U3P_SS_EP_COMPN_DESCR, /* SS endpoint companion descriptor type */ + (USB3_PACKETS_PER_BURST - 1), /* Max no. of packets in a burst : 0: burst 1 packet at a time */ + 0x00, /* Max streams for bulk EP = 0 (No streams) */ + 0x00,0x00 /* Service interval for the EP : 0 for bulk */ +}; + + /* Standard Language ID String Descriptor */ const uint8_t b200_string_lang_id_desc[] __attribute__ ((aligned (32))) = { diff --git a/firmware/octoclock/CMakeLists.txt b/firmware/octoclock/CMakeLists.txt index 80df0e9eb..0f2af35e9 100644 --- a/firmware/octoclock/CMakeLists.txt +++ b/firmware/octoclock/CMakeLists.txt @@ -31,7 +31,7 @@ if(NOT DEFINED PROGRAMMER) endif(NOT DEFINED PROGRAMMER) if(OCTOCLOCK_DEBUG) - message(STATUS "Debug enabled. Interrupts will be disabled.") + message(STATUS "Debug enabled.") add_definitions(-DDEBUG) endif(OCTOCLOCK_DEBUG) diff --git a/firmware/octoclock/bootloader/CMakeLists.txt b/firmware/octoclock/bootloader/CMakeLists.txt index 04bcfc492..7623a8698 100644 --- a/firmware/octoclock/bootloader/CMakeLists.txt +++ b/firmware/octoclock/bootloader/CMakeLists.txt @@ -49,7 +49,7 @@ add_custom_target( add_custom_target( upload_bootloader - ${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xFF:m -U flash:w:octoclock_bootloader.hex:i + ${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x80:m -U lfuse:w:0xEF:m -U flash:w:octoclock_bootloader.hex:i WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS octoclock_bootloader_hex COMMENT "Uploading OctoClock bootloader to device with ${PROGRAMMER}" diff --git a/firmware/octoclock/bootloader/main.c b/firmware/octoclock/bootloader/main.c index 5e2e6f17e..09f740d31 100644 --- a/firmware/octoclock/bootloader/main.c +++ b/firmware/octoclock/bootloader/main.c @@ -23,13 +23,13 @@ #include <avr/eeprom.h> #include <avr/io.h> #include <avr/pgmspace.h> +#include <avr/wdt.h> +#include <avrlibdefs.h> #include <octoclock.h> #include <debug.h> #include <network.h> -#include <util/delay.h> - #include <net/enc28j60.h> #include "octoclock/common.h" @@ -40,10 +40,19 @@ */ #define TIME_PASSED (TCNT1 > (TIMER1_ONE_SECOND*5) || (TIFR & _BV(TOV1))) -//States -static bool received_cmd = false; -static bool done_burning = false; +/* + * States + */ +static bool received_cmd = false; // Received "PREPARE_FW_BURN_CMD" signal +static bool done_burning = false; // Received "FINALIZE_BURNING_CMD" signal +static bool app_checked = false; // Ran validation check on firmware +/* + * After new firmware is burned onto the device, the bootloader calculates its + * CRC and burns it into the EEPROM. When the device boots, this CRC is used + * to validate the firmware before loading it. This struct represents how the + * information is stored in the EEPROM. + */ typedef struct { uint16_t fw_len; uint16_t fw_crc; @@ -51,15 +60,22 @@ typedef struct { static crc_info_t crc_info; +/* + * What actually burns the firmware onto the device. + * + * Source: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__boot.html + */ static void boot_program_page(uint8_t *buf, uint16_t page){ - uint16_t i; + // Disable interrupts + uint8_t sreg = SREG; + cli(); eeprom_busy_wait(); boot_page_erase(page); boot_spm_busy_wait(); // Wait until the memory is erased. - for(i = 0; i < SPM_PAGESIZE; i += 2){ + for(uint16_t i = 0; i < SPM_PAGESIZE; i += 2){ // Set up little-endian word. uint16_t w = *buf++; w += ((*buf++) << 8); @@ -68,36 +84,31 @@ static void boot_program_page(uint8_t *buf, uint16_t page){ } boot_page_write(page); // Store buffer in flash page. - boot_spm_busy_wait(); // Wait until the memory is written. + boot_spm_busy_wait(); // Wait until the memory is written. // Reenable RWW-section again. We need this if we want to jump back // to the application after bootloading. boot_rww_enable(); + + // Restore interrupt state + SREG = sreg; + sei(); } +/* + * Load firmware at given address into packet to send to host. + */ static void read_firmware(uint16_t addr, octoclock_packet_t *pkt_out){ for(size_t i = 0; i < SPM_PAGESIZE; i++){ pkt_out->data[i] = pgm_read_byte(addr+i); } } -void handle_udp_query_packet( - struct socket_address src, struct socket_address dst, - unsigned char *payload, int payload_len -){ - const octoclock_packet_t *pkt_in = (octoclock_packet_t*)payload; - - //Respond to query packets - if(pkt_in->code == OCTOCLOCK_QUERY_CMD){ - octoclock_packet_t pkt_out; - pkt_out.proto_ver = OCTOCLOCK_BOOTLOADER_PROTO_VER; - pkt_out.sequence = pkt_in->sequence; - pkt_out.code = OCTOCLOCK_QUERY_ACK; - pkt_out.len = 0; - send_udp_pkt(OCTOCLOCK_UDP_CTRL_PORT, src, (void*)&pkt_out, sizeof(octoclock_packet_t)); - } -} - +/* + * Calculate the CRC of the current firmware. + * + * Adapted from _crc16_update in <util/crc16.h>. + */ static void calculate_crc(uint16_t *crc, uint16_t len){ *crc = 0xFFFF; @@ -110,6 +121,11 @@ static void calculate_crc(uint16_t *crc, uint16_t len){ } } +/* + * Calculate the CRC of the current firmware. If it matches the + * CRC burned into the EEPROM, the firmware is considered valid, + * and the bootloader can load it. + */ static bool valid_app(){ crc_info_t crc_eeprom_info; eeprom_read_block(&crc_eeprom_info, (void*)OCTOCLOCK_EEPROM_APP_LEN, 4); @@ -118,6 +134,26 @@ static bool valid_app(){ return (crc_info.fw_crc == crc_eeprom_info.fw_crc); } +/* + * UDP handlers + */ +void handle_udp_query_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + const octoclock_packet_t *pkt_in = (octoclock_packet_t*)payload; + + // Respond to uhd::device::find(), identify as bootloader + if(pkt_in->code == OCTOCLOCK_QUERY_CMD){ + octoclock_packet_t pkt_out; + pkt_out.proto_ver = OCTOCLOCK_BOOTLOADER_PROTO_VER; + pkt_out.sequence = pkt_in->sequence; + pkt_out.code = OCTOCLOCK_QUERY_ACK; + pkt_out.len = 0; + send_udp_pkt(OCTOCLOCK_UDP_CTRL_PORT, src, (void*)&pkt_out, sizeof(octoclock_packet_t)); + } +} + void handle_udp_fw_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len @@ -132,24 +168,27 @@ void handle_udp_fw_packet( case PREPARE_FW_BURN_CMD: received_cmd = true; done_burning = false; + crc_info.fw_crc = pkt_in->crc; crc_info.fw_len = pkt_in->len; pkt_out.code = FW_BURN_READY_ACK; break; + // Burn firmware sent from the host case FILE_TRANSFER_CMD: boot_program_page(pkt_in->data, pkt_in->addr); pkt_out.code = FILE_TRANSFER_ACK; + pkt_out.addr = pkt_in->addr; break; + // Send firmware back to the host for verification case READ_FW_CMD: pkt_out.code = READ_FW_ACK; read_firmware(pkt_in->addr, &pkt_out); break; + // Calculate the CRC of the new firmware and finish case FINALIZE_BURNING_CMD: - //With stuff verified, burn CRC info into EEPROM done_burning = true; - calculate_crc(&(crc_info.fw_crc), crc_info.fw_len); eeprom_write_block(&crc_info, (void*)OCTOCLOCK_EEPROM_APP_LEN, 4); pkt_out.code = FINALIZE_BURNING_ACK; break; @@ -170,11 +209,12 @@ void handle_udp_eeprom_packet( pkt_out.sequence = pkt_in->sequence; pkt_out.len = 0; + // Restore OctoClock's EEPROM to factory state if(pkt_in->proto_ver == OCTOCLOCK_FW_COMPAT_NUM){ switch(pkt_in->code){ case CLEAR_EEPROM_CMD: received_cmd = true; - uint8_t blank_eeprom[103]; + uint8_t blank_eeprom[103]; // 103 is offset of CRC info memset(blank_eeprom, 0xFF, 103); eeprom_write_block(blank_eeprom, 0, 103); pkt_out.code = CLEAR_EEPROM_ACK; @@ -189,28 +229,45 @@ void handle_udp_eeprom_packet( int main(void){ - asm("cli"); + // Disable watchdog timer + wdt_disable(); + + // Give interrupts to bootloader + MCUCR = (1<<IVCE); + MCUCR = (1<<IVSEL); + cli(); - //Initialization + // Atmega128 setup_atmel_io_ports(); + + // Start timer + TIMER1_INIT(); + + // Ethernet stack network_init(); - init_udp_listeners(); register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_query_packet); register_udp_listener(OCTOCLOCK_UDP_FW_PORT, handle_udp_fw_packet); register_udp_listener(OCTOCLOCK_UDP_EEPROM_PORT, handle_udp_eeprom_packet); - //Turn LED's on to show we're in the bootloader + // Turn LED's on to show we're in the bootloader PORTC |= 0x20; PORTC |= (0x20<<1); PORTC |= (0x20<<2); - TIMER1_INIT(); - bool app_checked = false; - + /* + * This loop determines whether the OctoClock will remain in its bootloader + * state or if it will load the main firmware. After five seconds, it will + * check to see if valid firmware is installed. If so, it will immediately + * load it. Otherwise, it will remain here until firmware is installed. + * + * This process can be stopped by an instruction from the firmware burner + * utility, at which point the OctoClock will remain in bootloader state until + * instructed by the utility to exit the loop and load the new firmware. + */ while(true){ if(done_burning){ if(valid_app()) break; - else done_burning = false; //Burning somehow failed and wasn't caught + else done_burning = false; // Burning somehow failed and wasn't caught } if(!app_checked && !received_cmd && TIME_PASSED){ app_checked = true; @@ -220,16 +277,18 @@ int main(void){ network_check(); } - //Turn LED's off before moving to application + // Turn LED's off before moving to application PORTC &= ~0x20; PORTC &= ~(0x20<<1); PORTC &= ~(0x20<<2); /* - * Whether the bootloader reaches here through five seconds of inactivity - * or after a firmware burn just finished, it can be assumed that the application - * is valid. + * At this point, the bootloader has determined that there is valid + * firmware installed on the device and that it is OK to load it. */ + TIMER1_DISABLE(); + MCUCR = (1<<IVCE); + MCUCR = 0; + cli(); asm("jmp 0000"); - return 0; //Will never get here, but AVR-GCC needs it } diff --git a/firmware/octoclock/include/clkdist.h b/firmware/octoclock/include/clkdist.h index 633df9ddf..357daf37b 100644 --- a/firmware/octoclock/include/clkdist.h +++ b/firmware/octoclock/include/clkdist.h @@ -23,7 +23,7 @@ #include <octoclock.h> typedef enum { - Reg0, Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7, + Reg0=0, Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7, Reg8_Status_Control, Read_Command=0xE, RAM_EEPROM_Unlock=0x1F, @@ -46,6 +46,8 @@ void reset_TI_CDCE18005(void); uint32_t get_TI_CDCE18005(CDCE18005 which_register); +void set_TI_CDCE18005(CDCE18005 which_register, uint32_t bits); + bool check_TI_CDCE18005(TI_Input_10_MHz which_input, CDCE18005 which_register); #endif /* _CLKDIST_H_ */ diff --git a/firmware/octoclock/include/debug.h b/firmware/octoclock/include/debug.h index ee0618bc6..1f69896f0 100644 --- a/firmware/octoclock/include/debug.h +++ b/firmware/octoclock/include/debug.h @@ -66,8 +66,8 @@ DEBUG_LOG_HEX(((uint8_t*)&num)[0]); #define DEBUG_LOG_INT(num) DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[3]); \ - DEBUG_LOG_HEX(((uint8_t*)&num)[2]); \ - DEBUG_LOG_HEX(((uint8_t*)&num)[1]); \ + DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[2]); \ + DEBUG_LOG_HEX_NNL(((uint8_t*)&num)[1]); \ DEBUG_LOG_HEX(((uint8_t*)&num)[0]); #else diff --git a/firmware/octoclock/include/gpsdo.h b/firmware/octoclock/include/gpsdo.h index fc7d87324..df0440404 100644 --- a/firmware/octoclock/include/gpsdo.h +++ b/firmware/octoclock/include/gpsdo.h @@ -27,6 +27,4 @@ gpsdo_cache_state_t gpsdo_state; void send_gpsdo_cmd(char* buf, uint8_t size); -void process_gpsdo_output(void); - #endif /* _GPSDO_H_ */ diff --git a/firmware/octoclock/include/net/enc28j60.h b/firmware/octoclock/include/net/enc28j60.h index 463303f3c..dc58b451b 100644 --- a/firmware/octoclock/include/net/enc28j60.h +++ b/firmware/octoclock/include/net/enc28j60.h @@ -1,299 +1,276 @@ -/*! \file enc28j60.h \brief Microchip ENC28J60 Ethernet Interface Driver. */ -//***************************************************************************** -// -// File Name : 'enc28j60.h' -// Title : Microchip ENC28J60 Ethernet Interface Driver -// Author : Pascal Stang (c)2005 -// Created : 9/22/2005 -// Revised : 9/22/2005 -// Version : 0.1 -// Target MCU : Atmel AVR series -// Editor Tabs : 4 -// -/// \ingroup network -/// \defgroup enc28j60 Microchip ENC28J60 Ethernet Interface Driver (enc28j60.c) -/// \code #include "net/enc28j60.h" \endcode -/// \par Overview -/// This driver provides initialization and transmit/receive -/// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY. -/// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin -/// chip, using an SPI interface to the host processor. -/// -// -//***************************************************************************** -//@{ +/* + * Copyright 2015 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ -#ifndef ENC28J60_H -#define ENC28J60_H +#ifndef _NET_ENC28J60_H_ +#define _NET_ENC28J60_H_ -#include <avrlibdefs.h> +#include <avr/io.h> -#include "enc28j60conf.h" +#define SPI_DDR DDRB +#define SPI_PORT PORTB +#define SPI_CS 0 +#define SPI_MOSI 2 +#define SPI_MISO 3 +#define SPI_SCK 1 -// ENC28J60 Control Registers -// Control register definitions are a combination of address, -// bank number, and Ethernet/MAC/PHY indicator bits. -// - Register address (bits 0-4) -// - Bank number (bits 5-6) -// - MAC/PHY indicator (bit 7) -#define ADDR_MASK 0x1F -#define BANK_MASK 0x60 -#define SPRD_MASK 0x80 -// All-bank registers -#define EIE 0x1B -#define EIR 0x1C -#define ESTAT 0x1D -#define ECON2 0x1E -#define ECON1 0x1F -// Bank 0 registers -#define ERDPTL (0x00|0x00) -#define ERDPTH (0x01|0x00) -#define EWRPTL (0x02|0x00) -#define EWRPTH (0x03|0x00) -#define ETXSTL (0x04|0x00) -#define ETXSTH (0x05|0x00) -#define ETXNDL (0x06|0x00) -#define ETXNDH (0x07|0x00) -#define ERXSTL (0x08|0x00) -#define ERXSTH (0x09|0x00) -#define ERXNDL (0x0A|0x00) -#define ERXNDH (0x0B|0x00) -#define ERXRDPTL (0x0C|0x00) -#define ERXRDPTH (0x0D|0x00) -#define ERXWRPTL (0x0E|0x00) -#define ERXWRPTH (0x0F|0x00) -#define EDMASTL (0x10|0x00) -#define EDMASTH (0x11|0x00) -#define EDMANDL (0x12|0x00) -#define EDMANDH (0x13|0x00) -#define EDMADSTL (0x14|0x00) -#define EDMADSTH (0x15|0x00) -#define EDMACSL (0x16|0x00) -#define EDMACSH (0x17|0x00) -// Bank 1 registers -#define EHT0 (0x00|0x20) -#define EHT1 (0x01|0x20) -#define EHT2 (0x02|0x20) -#define EHT3 (0x03|0x20) -#define EHT4 (0x04|0x20) -#define EHT5 (0x05|0x20) -#define EHT6 (0x06|0x20) -#define EHT7 (0x07|0x20) -#define EPMM0 (0x08|0x20) -#define EPMM1 (0x09|0x20) -#define EPMM2 (0x0A|0x20) -#define EPMM3 (0x0B|0x20) -#define EPMM4 (0x0C|0x20) -#define EPMM5 (0x0D|0x20) -#define EPMM6 (0x0E|0x20) -#define EPMM7 (0x0F|0x20) -#define EPMCSL (0x10|0x20) -#define EPMCSH (0x11|0x20) -#define EPMOL (0x14|0x20) -#define EPMOH (0x15|0x20) -#define EWOLIE (0x16|0x20) -#define EWOLIR (0x17|0x20) -#define ERXFCON (0x18|0x20) -#define EPKTCNT (0x19|0x20) -// Bank 2 registers -#define MACON1 (0x00|0x40|0x80) -#define MACON2 (0x01|0x40|0x80) -#define MACON3 (0x02|0x40|0x80) -#define MACON4 (0x03|0x40|0x80) -#define MABBIPG (0x04|0x40|0x80) -#define MAIPGL (0x06|0x40|0x80) -#define MAIPGH (0x07|0x40|0x80) -#define MACLCON1 (0x08|0x40|0x80) -#define MACLCON2 (0x09|0x40|0x80) -#define MAMXFLL (0x0A|0x40|0x80) -#define MAMXFLH (0x0B|0x40|0x80) -#define MAPHSUP (0x0D|0x40|0x80) -#define MICON (0x11|0x40|0x80) -#define MICMD (0x12|0x40|0x80) -#define MIREGADR (0x14|0x40|0x80) -#define MIWRL (0x16|0x40|0x80) -#define MIWRH (0x17|0x40|0x80) -#define MIRDL (0x18|0x40|0x80) -#define MIRDH (0x19|0x40|0x80) -// Bank 3 registers -#define MAADR1 (0x00|0x60|0x80) -#define MAADR0 (0x01|0x60|0x80) -#define MAADR3 (0x02|0x60|0x80) -#define MAADR2 (0x03|0x60|0x80) -#define MAADR5 (0x04|0x60|0x80) -#define MAADR4 (0x05|0x60|0x80) -#define EBSTSD (0x06|0x60) -#define EBSTCON (0x07|0x60) -#define EBSTCSL (0x08|0x60) -#define EBSTCSH (0x09|0x60) -#define MISTAT (0x0A|0x60|0x80) -#define EREVID (0x12|0x60) -#define ECOCON (0x15|0x60) -#define EFLOCON (0x17|0x60) -#define EPAUSL (0x18|0x60) -#define EPAUSH (0x19|0x60) -// PHY registers -#define PHCON1 0x00 -#define PHSTAT1 0x01 -#define PHHID1 0x02 -#define PHHID2 0x03 -#define PHCON2 0x10 -#define PHSTAT2 0x11 -#define PHIE 0x12 -#define PHIR 0x13 -#define PHLCON 0x14 +// Register Masks +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 -// ENC28J60 EIE Register Bit Definitions -#define EIE_INTIE 0x80 -#define EIE_PKTIE 0x40 -#define EIE_DMAIE 0x20 -#define EIE_LINKIE 0x10 -#define EIE_TXIE 0x08 -#define EIE_WOLIE 0x04 -#define EIE_TXERIE 0x02 -#define EIE_RXERIE 0x01 -// ENC28J60 EIR Register Bit Definitions -#define EIR_PKTIF 0x40 -#define EIR_DMAIF 0x20 -#define EIR_LINKIF 0x10 -#define EIR_TXIF 0x08 -#define EIR_WOLIF 0x04 -#define EIR_TXERIF 0x02 -#define EIR_RXERIF 0x01 -// ENC28J60 ESTAT Register Bit Definitions -#define ESTAT_INT 0x80 -#define ESTAT_LATECOL 0x10 -#define ESTAT_RXBUSY 0x04 -#define ESTAT_TXABRT 0x02 -#define ESTAT_CLKRDY 0x01 -// ENC28J60 ECON2 Register Bit Definitions -#define ECON2_AUTOINC 0x80 -#define ECON2_PKTDEC 0x40 -#define ECON2_PWRSV 0x20 -#define ECON2_VRPS 0x08 -// ENC28J60 ECON1 Register Bit Definitions -#define ECON1_TXRST 0x80 -#define ECON1_RXRST 0x40 -#define ECON1_DMAST 0x20 -#define ECON1_CSUMEN 0x10 -#define ECON1_TXRTS 0x08 -#define ECON1_RXEN 0x04 -#define ECON1_BSEL1 0x02 -#define ECON1_BSEL0 0x01 -// ENC28J60 MACON1 Register Bit Definitions -#define MACON1_LOOPBK 0x10 -#define MACON1_TXPAUS 0x08 -#define MACON1_RXPAUS 0x04 -#define MACON1_PASSALL 0x02 -#define MACON1_MARXEN 0x01 -// ENC28J60 MACON2 Register Bit Definitions -#define MACON2_MARST 0x80 -#define MACON2_RNDRST 0x40 -#define MACON2_MARXRST 0x08 -#define MACON2_RFUNRST 0x04 -#define MACON2_MATXRST 0x02 -#define MACON2_TFUNRST 0x01 -// ENC28J60 MACON3 Register Bit Definitions -#define MACON3_PADCFG2 0x80 -#define MACON3_PADCFG1 0x40 -#define MACON3_PADCFG0 0x20 -#define MACON3_TXCRCEN 0x10 -#define MACON3_PHDRLEN 0x08 -#define MACON3_HFRMLEN 0x04 -#define MACON3_FRMLNEN 0x02 -#define MACON3_FULDPX 0x01 -// ENC28J60 MICMD Register Bit Definitions -#define MICMD_MIISCAN 0x02 -#define MICMD_MIIRD 0x01 -// ENC28J60 MISTAT Register Bit Definitions -#define MISTAT_NVALID 0x04 -#define MISTAT_SCAN 0x02 -#define MISTAT_BUSY 0x01 -// ENC28J60 PHY PHCON1 Register Bit Definitions -#define PHCON1_PRST 0x8000 -#define PHCON1_PLOOPBK 0x4000 -#define PHCON1_PPWRSV 0x0800 -#define PHCON1_PDPXMD 0x0100 -// ENC28J60 PHY PHSTAT1 Register Bit Definitions -#define PHSTAT1_PFDPX 0x1000 -#define PHSTAT1_PHDPX 0x0800 -#define PHSTAT1_LLSTAT 0x0004 -#define PHSTAT1_JBSTAT 0x0002 -// ENC28J60 PHY PHCON2 Register Bit Definitions -#define PHCON2_FRCLINK 0x4000 -#define PHCON2_TXDIS 0x2000 -#define PHCON2_JABBER 0x0400 -#define PHCON2_HDLDIS 0x0100 +// All Banks Registers +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F -// ENC28J60 Packet Control Byte Bit Definitions -#define PKTCTRL_PHUGEEN 0x08 -#define PKTCTRL_PPADEN 0x04 -#define PKTCTRL_PCRCEN 0x02 -#define PKTCTRL_POVERRIDE 0x01 +// Bank 0 Registers +#define ERDPTL 0x00 +#define ERDPTH 0x01 +#define EWRPTL 0x02 +#define EWRPTH 0x03 +#define ETXSTL 0x04 +#define ETXSTH 0x05 +#define ETXNDL 0x06 +#define ETXNDH 0x07 +#define ERXSTL 0x08 +#define ERXSTH 0x09 +#define ERXNDL 0x0A +#define ERXNDH 0x0B +#define ERXRDPTL 0x0C +#define ERXRDPTH 0x0D +#define ERXWRPTL 0x0E +#define ERXWRPTH 0x0F +#define EDMASTL 0x10 +#define EDMASTH 0x11 +#define EDMANDL 0x12 +#define EDMANDH 0x13 +#define EDMADSTL 0x14 +#define EDMADSTH 0x15 +#define EDMACSL 0x16 +#define EDMACSH 0x17 -// SPI operation codes -#define ENC28J60_READ_CTRL_REG 0x00 -#define ENC28J60_READ_BUF_MEM 0x3A -#define ENC28J60_WRITE_CTRL_REG 0x40 -#define ENC28J60_WRITE_BUF_MEM 0x7A -#define ENC28J60_BIT_FIELD_SET 0x80 -#define ENC28J60_BIT_FIELD_CLR 0xA0 -#define ENC28J60_SOFT_RESET 0xFF +// Bank 1 Registers +#define EHT0 0x20 +#define EHT1 0x21 +#define EHT2 0x22 +#define EHT3 0x23 +#define EHT4 0x24 +#define EHT5 0x25 +#define EHT6 0x26 +#define EHT7 0x27 +#define EPMM0 0x28 +#define EPMM1 0x29 +#define EPMM2 0x2A +#define EPMM3 0x2B +#define EPMM4 0x2C +#define EPMM5 0x2D +#define EPMM6 0x2E +#define EPMM7 0x2F +#define EPMCSL 0x30 +#define EPMCSH 0x31 +#define EPMOL 0x34 +#define EPMOH 0x35 +#define EWOLIE 0x36 +#define EWOLIR 0x37 +#define ERXFCON 0x38 +#define EPKTCNT 0x39 +// Bank 2 Register +#define MACON1 0xC0 +#define MACON2 0xC1 +#define MACON3 0xC2 +#define MACON4 0xC3 +#define MABBIPG 0xC4 +#define MAIPGL 0xC6 +#define MAIPGH 0xC7 +#define MACLCON1 0xC8 +#define MACLCON2 0xC9 +#define MAMXFLL 0xCA +#define MAMXFLH 0xCB +#define MAPHSUP 0xCD +#define MICON 0xD1 +#define MICMD 0xD2 +#define MIREGADR 0xD4 +#define MIWRL 0xD6 +#define MIWRH 0xD7 +#define MIRDL 0xD8 +#define MIRDH 0xD9 -// buffer boundaries applied to internal 8K ram -// entire available packet buffer space is allocated -#define TXSTART_INIT 0x0000 // start TX buffer at 0 -#define RXSTART_INIT 0x0600 // give TX buffer space for one full ethernet frame (~1500 bytes) -#define RXSTOP_INIT 0x1FFF // receive buffer gets the rest +// Bank 3 Registers +#define MAADR1 0xE0 +#define MAADR0 0xE1 +#define MAADR3 0xE2 +#define MAADR2 0xE3 +#define MAADR5 0xE4 +#define MAADR4 0xE5 +#define EBSTSD 0x66 +#define EBSTCON 0x67 +#define EBSTCSL 0x68 +#define EBSTCSH 0x69 +#define MISTAT 0xEA +#define EREVID 0x72 +#define ECOCON 0x75 +#define EFLOCON 0x77 +#define EPAUSL 0x78 +#define EPAUSH 0x79 -#define MAX_FRAMELEN 1518 // maximum ethernet frame length +// PHY Registers +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 -// Ethernet constants -#define ETHERNET_MIN_PACKET_LENGTH 0x3C -//#define ETHERNET_HEADER_LENGTH 0x0E +// ERXFCON bit definitions +#define UCEN 0x80 +#define ANDOR 0x40 +#define CRCEN 0x20 +#define PMEN 0x10 +#define MPEN 0x08 +#define HTEN 0x04 +#define MCEN 0x02 +#define BCEN 0x01 -// setup ports for I/O -//void ax88796SetupPorts(void); +// EIE bit definitions +#define INTIE 0x80 +#define PKTIE 0x40 +#define DMAIE 0x20 +#define LINKIE 0x10 +#define TXIE 0x08 +#define WOLIE 0x04 +#define TXERIE 0x02 +#define RXERIE 0x01 -//! do a ENC28J60 read operation -u08 enc28j60ReadOp(u08 op, u08 address); -//! do a ENC28J60 write operation -void enc28j60WriteOp(u08 op, u08 address, u08 data); -//! read the packet buffer memory -void enc28j60ReadBuffer(u16 len, u08* data); -//! write the packet buffer memory -void enc28j60WriteBuffer(u16 len, u08* data); -//! set the register bank for register at address -void enc28j60SetBank(u08 address); -//! read ax88796 register -u08 enc28j60Read(u08 address); -//! write ax88796 register -void enc28j60Write(u08 address, u08 data); -//! read a PHY register -u16 enc28j60PhyRead(u08 address); -//! write a PHY register -void enc28j60PhyWrite(u08 address, u16 data); +// EIR bit definitions +#define PKTIF 0x40 +#define DMAIF 0x20 +#define LINKIF 0x10 +#define TXIF 0x08 +#define WOLIF 0x04 +#define TXERIF 0x02 +#define RXERIF 0x01 -//! initialize the ethernet interface for transmit/receive -void enc28j60Init(u08* macaddr); +// ESTAT bit definitions +#define INT 0x80 +#define LATECOL 0x10 +#define RXBUSY 0x04 +#define TXABRT 0x02 +#define CLKRDY 0x01 -//! Packet transmit function. -/// Sends a packet on the network. It is assumed that the packet is headed by a valid ethernet header. -/// \param len Length of packet in bytes. -/// \param packet Pointer to packet data. -/// \param len2 Length of the secound packet in bytes, can be 0. -/// \param packet2 Pointer to the secound packet data, can be NULL. -void enc28j60PacketSend(unsigned int len1, unsigned char* packet1, unsigned int len2, unsigned char* packet2); +// ECON2 bit definitions +#define AUTOINC 0x80 +#define PKTDEC 0x40 +#define PWRSV 0x20 +#define VRPS 0x08 -//! Packet receive function. -/// Gets a packet from the network receive buffer, if one is available. -/// The packet will by headed by an ethernet header. -/// \param maxlen The maximum acceptable length of a retrieved packet. -/// \param buf Pointer to buffer. -/// \return Packet length in bytes if a packet was retrieved, zero otherwise. -unsigned int enc28j60PacketReceive(unsigned int maxlen, u08* buf); +// ECON1 bit definitions +#define TXRST 0x80 +#define RXRST 0x40 +#define DMAST 0x20 +#define CSUMEN 0x10 +#define TXRTS 0x08 +#define ENCRXEN 0x04 +#define BSEL1 0x02 +#define BSEL0 0x01 -#endif -//@} +// MACON1 bit definitions +#define LOOPBK 0x10 +#define TXPAUS 0x08 +#define RXPAUS 0x04 +#define PASSALL 0x02 +#define MARXEN 0x01 +// MACON2 bit definitions +#define MARST 0x80 +#define RNDRST 0x40 +#define MARXRST 0x08 +#define RFUNRST 0x04 +#define MATXRST 0x02 +#define TFUNRST 0x01 + +// MACON3 bit definitions +#define PADCFG2 0x80 +#define PADCFG1 0x40 +#define PADCFG0 0x20 +#define TXCRCEN 0x10 +#define PHDRLEN 0x08 +#define HFRMLEN 0x04 +#define FRMLNEN 0x02 +#define FULDPX 0x01 + +// MICMD bit definitions +#define MIISCAN 0x02 +#define MIIRD 0x01 + +// MISTAT bit definitions +#define NVALID 0x04 +#define SCAN 0x02 +#define BUSY 0x01 + +// PHCON1 bit definitions +#define PRST 0x8000 +#define PLOOPBK 0x4000 +#define PPWRSV 0x0800 +#define PDPXMD 0x0100 + +// PHSTAT1 bit definitions +#define PFDPX 0x1000 +#define PHDPX 0x0800 +#define LLSTAT 0x0004 +#define JBSTAT 0x0002 + +// PHCON2 bit definitions +#define FRCLINK 0x4000 +#define TXDIS 0x2000 +#define JABBER 0x0400 +#define HDLDIS 0x0100 + +// Packet Control bit Definitions +#define PHUGEEN 0x08 +#define PPADEN 0x04 +#define PCRCEN 0x02 +#define POVERRIDE 0x01 + +// SPI Instruction Set +#define RCR 0x00 // Read Control Register +#define RBM 0x3A // Read Buffer Memory +#define WCR 0x40 // Write Control Register +#define WBM 0x7A // Write Buffer Memory +#define BFS 0x80 // Bit Field Set +#define BFC 0xA0 // Bit Field Clear +#define SC 0xFF // Soft Reset + +// Buffer +#define RXSTART_INIT 0x0000 +#define RXSTOP_INIT (0x1FFF-0x0600-1) +#define TXSTART_INIT (0x1FFF-0x0600) +#define TXSTOP_INIT 0x1FFF +#define MAX_FRAMELEN 1500 + +void enc28j60_init(uint8_t* mac_addr); + +uint16_t enc28j60_recv(uint8_t* buffer, uint16_t max_len); + +void enc28j60_send(uint8_t* buffer, uint16_t len); + +#endif /* _NET_ENC28J60_H_ */ diff --git a/firmware/octoclock/include/net/enc28j60conf.h b/firmware/octoclock/include/net/enc28j60conf.h deleted file mode 100644 index 0acf5473c..000000000 --- a/firmware/octoclock/include/net/enc28j60conf.h +++ /dev/null @@ -1,49 +0,0 @@ -/*! \file enc28j60conf.h \brief Microchip ENC28J60 Ethernet Interface Driver Configuration. */ -//***************************************************************************** -// -// File Name : 'enc28j60conf.h' -// Title : Microchip ENC28J60 Ethernet Interface Driver Configuration -// Author : Pascal Stang -// Created : 10/5/2004 -// Revised : 8/22/2005 -// Version : 0.1 -// Target MCU : Atmel AVR series -// Editor Tabs : 4 -// -// Description : This driver provides initialization and transmit/receive -// functions for the ENC28J60 10Mb Ethernet Controller and PHY. -// -// This code is distributed under the GNU Public License -// which can be found at http://www.gnu.org/licenses/gpl.txt -// -//***************************************************************************** - -#ifndef ENC28J60CONF_H -#define ENC28J60CONF_H - -#include <stdint.h> -typedef uint8_t u08; -typedef uint16_t u16; -typedef uint32_t u32; - -// ENC28J60 SPI port -#define ENC28J60_SPI_PORT PORTB -#define ENC28J60_SPI_DDR DDRB -#define ENC28J60_SPI_SCK PORTB1 -#define ENC28J60_SPI_MOSI PORTB2 -#define ENC28J60_SPI_MISO PORTB3 -#define ENC28J60_SPI_SS PORTB0 -// ENC28J60 control port -#define ENC28J60_CONTROL_PORT PORTB -#define ENC28J60_CONTROL_DDR DDRB -#define ENC28J60_CONTROL_CS PORTB0 - -// MAC address for this interface -#define ENC28J60_MAC0 '0' -#define ENC28J60_MAC1 'F' -#define ENC28J60_MAC2 'F' -#define ENC28J60_MAC3 'I' -#define ENC28J60_MAC4 'C' -#define ENC28J60_MAC5 'E' - -#endif /* ENC28J60CONF_H */ diff --git a/firmware/octoclock/include/net/eth_mac_addr.h b/firmware/octoclock/include/net/eth_mac_addr.h index 0c790aa4f..78986bf04 100644 --- a/firmware/octoclock/include/net/eth_mac_addr.h +++ b/firmware/octoclock/include/net/eth_mac_addr.h @@ -21,11 +21,8 @@ #include <stdint.h> // Ethernet MAC address - -#pragma pack(push,1) typedef struct { uint8_t addr[6]; -} eth_mac_addr_t; -#pragma pack(pop) +} eth_mac_addr_t __attribute__((aligned(1))); #endif /* INCLUDED_ETH_MAC_ADDR_H */ diff --git a/firmware/octoclock/include/network.h b/firmware/octoclock/include/network.h index 83e398bc5..6d126a197 100644 --- a/firmware/octoclock/include/network.h +++ b/firmware/octoclock/include/network.h @@ -69,17 +69,11 @@ #define _IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (_IPH_TTL(hdr) << 8))) #define _IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) -bool using_network_defaults; +volatile bool using_network_defaults; // Ethernet I/O buffers -uint8_t buf_in[512]; -uint8_t buf_out[512]; - -// Default values loaded if EEPROM is incomplete -static const uint32_t blank_eeprom_ip = _IP(255,255,255,255); -static const uint32_t default_ip = _IP(192,168,10,3); -static const uint32_t default_dr = _IP(192,168,10,1); -static const uint32_t default_netmask = _IP(255,255,255,0); +#define ETH_BUF_SIZE 512 +uint8_t eth_buf[ETH_BUF_SIZE]; typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len); diff --git a/firmware/octoclock/include/octoclock.h b/firmware/octoclock/include/octoclock.h index 849ab7f96..34cad1c12 100644 --- a/firmware/octoclock/include/octoclock.h +++ b/firmware/octoclock/include/octoclock.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Ettus Research LLC + * Copyright 2014-2015 Ettus Research LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,26 +24,21 @@ #include <stdint.h> // Define frequency -#define F_CPU 12500000UL +#define F_CPU 7372800UL /* - * Timer 0 (8-bit) - * * Set prescaler to 8 - * * Enable overflow interrupt - * * Set timer to 0 - */ -#define TIMER0_INIT() TCCR0 = (1 << CS01); \ - TIMSK |= (1 << TOIE0); \ - TCNT0 = 0; -/* * Timer 1 (16-bit) * * Set prescaler to 1024 * * Enable overflow interrupt * * Set timer to 0 */ #define TIMER1_INIT() TCCR1B = (1 << CS12) | (1 << CS10); \ - TIMSK |= (1<<TOIE1); \ - TCNT1 = 0; + TIMSK |= (1<<TOIE1); \ + TCNT1 = 0; + +#define TIMER1_DISABLE() TCCR1B = 0; \ + TIMSK = 0; \ + TCNT1 = 0; #define TIMER1_ONE_SECOND ((uint32_t)(12207)) @@ -94,12 +89,6 @@ * Bits_32(10000000,11111111,10101010,01010101) = 2164238933 */ -typedef enum { - Top, - Middle, - Bottom -} LEDs; - void setup_atmel_io_ports(void); #endif /* _OCTOCLOCK_H_ */ diff --git a/firmware/octoclock/include/state.h b/firmware/octoclock/include/state.h index 9734948cf..2170c2638 100644 --- a/firmware/octoclock/include/state.h +++ b/firmware/octoclock/include/state.h @@ -22,23 +22,24 @@ #include <octoclock.h> -// NOT PRESENT unless proven so... -static ref_t global_which_ref = NO_REF; -static bool global_gps_present = false; -static bool global_ext_ref_is_present = false; +// Global state variables +extern volatile bool g_ext_ref_present; +extern volatile bool g_gps_present; +extern volatile switch_pos_t g_switch_pos; +extern volatile ref_t g_ref; -void led(LEDs which, int turn_it_on); +typedef enum { + LED_TOP, // Internal + LED_MIDDLE, // External + LED_BOTTOM // Status +} led_t; -void LEDs_off(void); +void led(led_t which, bool on); -void force_internal(void); +void leds_off(void); void prefer_internal(void); void prefer_external(void); -ref_t which_ref(void); - -switch_pos_t get_switch_pos(void); - #endif /* _STATE_H_ */ diff --git a/firmware/octoclock/include/usart.h b/firmware/octoclock/include/usart.h index 35ee9eb95..203255988 100644 --- a/firmware/octoclock/include/usart.h +++ b/firmware/octoclock/include/usart.h @@ -25,10 +25,6 @@ void usart_init(void); char usart_getc(void); -char usart_getc_noblock(void); - void usart_putc(char ch); -void usart_putc_nowait(char ch); - #endif /* _USART_H_ */ diff --git a/firmware/octoclock/lib/clkdist.c b/firmware/octoclock/lib/clkdist.c index ed29510b6..0468ac38e 100644 --- a/firmware/octoclock/lib/clkdist.c +++ b/firmware/octoclock/lib/clkdist.c @@ -21,6 +21,8 @@ #include <clkdist.h> #include <state.h> +#include <util/delay.h> + #define wait() for(uint16_t u=14000; u; u--) asm("nop"); #define CLK (PA0) // Shift by 0 bits @@ -33,7 +35,7 @@ // Table of 32-bit constants to be written to the TI chip's registers. These are // from the "Special Settings" on Page 35 of the datasheet. // For the GPS's 10 MHz output -static uint32_t table_Pri_Ref[] = { +static const uint32_t table_Pri_Ref[] = { Bits_32(1,01010100,0,0), // Reg 0 Bits_32(1,01010100,0,0), // Outputs LVCMOS Positive&Negative Active - Non-inverted Bits_32(1,01010100,0,0), @@ -47,7 +49,7 @@ static uint32_t table_Pri_Ref[] = { // For the External 10 MHz input LVDS with external termination, // Effectively DC coupled -static uint32_t table_Sec_Ref[] = { +static const uint32_t table_Sec_Ref[] = { Bits_32(0001,01010100,0,100000), // Reg 0 -- use Secondary Reference for all channels Bits_32(0001,01010100,0,100000), // Outputs LVCMOS Positive&Negative Active - Non-inverted Bits_32(0001,01010100,0,100000), @@ -81,7 +83,6 @@ static bool get_bit(uint8_t bit_number) { // Send 32 bits to TI chip, LSB first. // Don't worry about reading any bits back at this time static void send_SPI(uint32_t bits) { - // Basically, when the clock is low, one can set MOSI to anything, as it's // ignored. set_bit(CE_, Lo); // Start SPI transaction with TI chip @@ -130,7 +131,8 @@ void setup_TI_CDCE18005(TI_Input_10_MHz which_input) { for(uint8_t i=0; i<table_size; i++){ temp = table_Pri_Ref[i]<<4; temp |= i; - send_SPI(temp); // Make sure the register's address is in the LSBs + // Make sure the register's address is in the LSBs + send_SPI(temp); } } else { // is Secondary_Ext -- External 10 MHz input from SMA connector @@ -169,6 +171,10 @@ uint32_t get_TI_CDCE18005(CDCE18005 which_register){ return receive_SPI(); } +void set_TI_CDCE18005(CDCE18005 which_register, uint32_t bits){ + send_SPI((bits << 4) | which_register); +} + bool check_TI_CDCE18005(TI_Input_10_MHz which_input, CDCE18005 which_register) { diff --git a/firmware/octoclock/lib/enc28j60.c b/firmware/octoclock/lib/enc28j60.c index f0bbee0e7..ead7e4ec8 100644 --- a/firmware/octoclock/lib/enc28j60.c +++ b/firmware/octoclock/lib/enc28j60.c @@ -1,337 +1,211 @@ -/*! \file enc28j60.c \brief Microchip ENC28J60 Ethernet Interface Driver. */ -//***************************************************************************** -// -// File Name : 'enc28j60.c' -// Title : Microchip ENC28J60 Ethernet Interface Driver -// Author : Pascal Stang (c)2005 -// Created : 9/22/2005 -// Revised : 5/19/2014 -// Version : 0.1 -// Target MCU : Atmel AVR series -// Editor Tabs : 4 -// -// Description : This driver provides initialization and transmit/receive -// functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY. -// This chip is novel in that it is a full MAC+PHY interface all in a 28-pin -// chip, using an SPI interface to the host processor. -// -//***************************************************************************** +/* + * Copyright 2015 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include <octoclock.h> #include <net/enc28j60.h> -#include <net/enc28j60conf.h> -#include <avr/io.h> #include <util/delay.h> -u08 Enc28j60Bank; -u16 NextPacketPtr; - -u08 enc28j60ReadOp(u08 op, u08 address) -{ - u08 data; - - // assert CS - ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS); - - // issue read command - SPDR = op | (address & ADDR_MASK); - while(!(SPSR & (1<<SPIF))); - // read data - SPDR = 0x00; - while(!(SPSR & (1<<SPIF))); - // do dummy read if needed - if(address & 0x80) - { - SPDR = 0x00; - while(!(inb(SPSR) & (1<<SPIF))); - } - data = SPDR; - - // release CS - ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS); - - return data; -} +static uint8_t current_bank; +static uint16_t next_pkt_ptr; -void enc28j60WriteOp(u08 op, u08 address, u08 data) -{ - // assert CS - ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS); +#define SET_CS_ACTIVE() SPI_PORT &= ~(1<<SPI_CS); +#define SET_CS_PASSIVE() SPI_PORT |= (1<<SPI_CS); +#define SPI_WAIT() while(!(SPSR & (1<<SPIF))); - // issue write command - SPDR = op | (address & ADDR_MASK); - while(!(SPSR & (1<<SPIF))); - // write data - SPDR = data; - while(!(SPSR & (1<<SPIF))); +static uint8_t enc28j60_read_op(uint8_t op, uint8_t addr){ + SET_CS_ACTIVE(); + SPDR = (op | (addr & ADDR_MASK)); + SPI_WAIT(); + SPDR = 0x00; + SPI_WAIT(); - // release CS - ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS); -} + if(addr & 0x80){ + SPDR = 0x00; + SPI_WAIT(); + } -void enc28j60ReadBuffer(u16 len, u08* data) -{ - // assert CS - ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS); - - // issue read command - SPDR = ENC28J60_READ_BUF_MEM; - while(!(SPSR & (1<<SPIF))); - while(len--) - { - // read data - SPDR = 0x00; - while(!(SPSR & (1<<SPIF))); - *data++ = SPDR; - } - // release CS - ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS); + SET_CS_PASSIVE(); + return SPDR; } -void enc28j60WriteBuffer(u16 len, u08* data) -{ - // assert CS - ENC28J60_CONTROL_PORT &= ~(1<<ENC28J60_CONTROL_CS); - - // issue write command - SPDR = ENC28J60_WRITE_BUF_MEM; - while(!(SPSR & (1<<SPIF))); - while(len--) - { - // write data - SPDR = *data++; - while(!(SPSR & (1<<SPIF))); - } - // release CS - ENC28J60_CONTROL_PORT |= (1<<ENC28J60_CONTROL_CS); +static void enc28j60_write_op(uint8_t op, uint8_t addr, uint8_t value){ + SET_CS_ACTIVE(); + + SPDR = (op | (addr & ADDR_MASK)); + SPI_WAIT(); + SPDR = value; + SPI_WAIT(); + + SET_CS_PASSIVE(); } -void enc28j60SetBank(u08 address) -{ - // set the bank (if needed) - if((address & BANK_MASK) != Enc28j60Bank) - { - // set the bank - enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); - Enc28j60Bank = (address & BANK_MASK); - } +static void enc28j60_read_buffer(uint8_t* buf, uint16_t len){ + SET_CS_ACTIVE(); + + SPDR = RBM; + SPI_WAIT(); + while(len){ + len--; + SPDR = 0x00; + SPI_WAIT(); + *buf = SPDR; + buf++; + } + *buf = '\0'; + + SET_CS_PASSIVE(); } -u08 enc28j60Read(u08 address) -{ - // set the bank - enc28j60SetBank(address); - // do the read - return enc28j60ReadOp(ENC28J60_READ_CTRL_REG, address); +static void enc28j60_write_buffer(uint8_t* buf, uint16_t len){ + SET_CS_ACTIVE(); + + SPDR = WBM; + SPI_WAIT(); + while(len){ + len--; + SPDR = *buf; + buf++; + SPI_WAIT(); + } + + SET_CS_PASSIVE(); } -void enc28j60Write(u08 address, u08 data) -{ - // set the bank - enc28j60SetBank(address); - // do the write - enc28j60WriteOp(ENC28J60_WRITE_CTRL_REG, address, data); +static void enc28j60_set_bank(uint8_t addr){ + if((addr & BANK_MASK) != current_bank){ + enc28j60_write_op(BFC, ECON1, (BSEL1|BSEL0)); + enc28j60_write_op(BFS, ECON1, ((addr & BANK_MASK) >> 5)); + current_bank = (addr & BANK_MASK); + } } -u16 enc28j60PhyRead(u08 address) -{ - u16 data; - - // Set the right address and start the register read operation - enc28j60Write(MIREGADR, address); - enc28j60Write(MICMD, MICMD_MIIRD); - - // wait until the PHY read completes - while(enc28j60Read(MISTAT) & MISTAT_BUSY); - - // quit reading - enc28j60Write(MICMD, 0x00); - - // get data value - data = enc28j60Read(MIRDL); - data |= enc28j60Read(MIRDH); - // return the data - return data; +static uint8_t enc28j60_read(uint8_t addr){ + enc28j60_set_bank(addr); + return enc28j60_read_op(RCR, addr); } -void enc28j60PhyWrite(u08 address, u16 data) -{ - // set the PHY register address - enc28j60Write(MIREGADR, address); - - // write the PHY data - enc28j60Write(MIWRL, data); - enc28j60Write(MIWRH, data>>8); - - // wait until the PHY write completes - while(enc28j60Read(MISTAT) & MISTAT_BUSY); +static void enc28j60_write(uint8_t addr, uint16_t value){ + enc28j60_set_bank(addr); + enc28j60_write_op(WCR, addr, value); } -void enc28j60Init(u08* macaddr) -{ - // initialize I/O - sbi(ENC28J60_CONTROL_DDR, ENC28J60_CONTROL_CS); - sbi(ENC28J60_CONTROL_PORT, ENC28J60_CONTROL_CS); - - // setup SPI I/O pins - sbi(ENC28J60_SPI_PORT, ENC28J60_SPI_SCK); // set SCK hi - sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_SCK); // set SCK as output - cbi(ENC28J60_SPI_DDR, ENC28J60_SPI_MISO); // set MISO as input - sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_MOSI); // set MOSI as output - sbi(ENC28J60_SPI_DDR, ENC28J60_SPI_SS); // SS must be output for Master mode to work - // initialize SPI interface - // master mode - sbi(SPCR, MSTR); - // select clock phase positive-going in middle of data - cbi(SPCR, CPOL); - // Data order MSB first - cbi(SPCR,DORD); - // switch to f/4 2X = f/2 bitrate - cbi(SPCR, SPR0); - cbi(SPCR, SPR1); - sbi(SPSR, SPI2X); - // enable SPI - sbi(SPCR, SPE); - - // perform system reset - enc28j60WriteOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); - - /* - * "After sending an SPI Reset command, the PHY - * clock is stopped but the ESTAT.CLKRDY bit is not - * cleared. Therefore, polling the CLKRDY bit will not - * work to detect if the PHY is ready. - * - * Additionally, the hardware start-up time of 300 us - * may expire before the device is ready to operate. - * - * Work around - * After issuing the Reset command, wait at least - * 1 ms in firmware for the device to be ready." - * - * Source: http://ww1.microchip.com/downloads/en/DeviceDoc/80349c.pdf - */ - _delay_ms(1); - - // do bank 0 stuff - // initialize receive buffer - // 16-bit transfers, must write low byte first - // set receive buffer start address - NextPacketPtr = RXSTART_INIT; - enc28j60Write(ERXSTL, RXSTART_INIT&0xFF); - enc28j60Write(ERXSTH, RXSTART_INIT>>8); - // set receive pointer address - enc28j60Write(ERXRDPTL, RXSTART_INIT&0xFF); - enc28j60Write(ERXRDPTH, RXSTART_INIT>>8); - // set receive buffer end - // ERXND defaults to 0x1FFF (end of ram) - enc28j60Write(ERXNDL, RXSTOP_INIT&0xFF); - enc28j60Write(ERXNDH, RXSTOP_INIT>>8); - // set transmit buffer start - // ETXST defaults to 0x0000 (beginnging of ram) - enc28j60Write(ETXSTL, TXSTART_INIT&0xFF); - enc28j60Write(ETXSTH, TXSTART_INIT>>8); - - // do bank 2 stuff - // enable MAC receive - enc28j60Write(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); - // bring MAC out of reset - enc28j60Write(MACON2, 0x00); - // enable automatic padding and CRC operations - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); - // set inter-frame gap (non-back-to-back) - enc28j60Write(MAIPGL, 0x12); - enc28j60Write(MAIPGH, 0x0C); - // set inter-frame gap (back-to-back) - enc28j60Write(MABBIPG, 0x12); - // Set the maximum packet size which the controller will accept - enc28j60Write(MAMXFLL, MAX_FRAMELEN&0xFF); - enc28j60Write(MAMXFLH, MAX_FRAMELEN>>8); - - // do bank 3 stuff - // write MAC address - // NOTE: MAC address in ENC28J60 is byte-backward - enc28j60Write(MAADR5, macaddr[0]); - enc28j60Write(MAADR4, macaddr[1]); - enc28j60Write(MAADR3, macaddr[2]); - enc28j60Write(MAADR2, macaddr[3]); - enc28j60Write(MAADR1, macaddr[4]); - enc28j60Write(MAADR0, macaddr[5]); - - // no loopback of transmitted frames - enc28j60PhyWrite(PHCON2, PHCON2_HDLDIS); - - // switch to bank 0 - enc28j60SetBank(ECON1); - // enable interrutps - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); - // enable packet reception - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); +void enc28j60_init(uint8_t* mac_addr){ + SPI_DDR |= (1 << SPI_CS); + SET_CS_PASSIVE(); + + SPI_DDR |= ((1 << SPI_MOSI) | (1 << SPI_SCK)); + SPI_DDR &= ~(1 << SPI_MISO); + SPI_PORT &= ~(1 << SPI_MOSI); + SPI_PORT &= ~(1 << SPI_SCK); + SPCR = ((1 << SPE) | (1 << MSTR)); + SPSR |= (1 << SPI2X); + enc28j60_write_op(SC, 0, SC); + next_pkt_ptr = RXSTART_INIT; + + // Designate RX addresses + enc28j60_write(ERXSTL, (RXSTART_INIT & 0xFF)); + enc28j60_write(ERXSTH, (RXSTART_INIT >> 8)); + enc28j60_write(ERXNDL, (RXSTOP_INIT & 0xFF)); + enc28j60_write(ERXNDH, (RXSTOP_INIT >> 8)); + + // Designate TX addresses + enc28j60_write(ETXSTL, (TXSTART_INIT & 0xFF)); + enc28j60_write(ETXSTH, (TXSTART_INIT >> 8)); + enc28j60_write(ETXNDL, (TXSTOP_INIT & 0xFF)); + enc28j60_write(ETXNDH, (TXSTOP_INIT >> 8)); + + // Configure filters + enc28j60_write(ERXFCON, (UCEN|CRCEN|PMEN|BCEN)); + enc28j60_write(EPMM0, 0x3F); + enc28j60_write(EPMM1, 0x30); + enc28j60_write(EPMCSL, 0xF9); + enc28j60_write(EPMCSH, 0xF7); + + // MAC initialization + enc28j60_write(MACON1, (MARXEN|TXPAUS|RXPAUS)); + enc28j60_write(MACON2, 0x00); + enc28j60_write_op(BFS, MACON3, (PADCFG0|TXCRCEN|FRMLNEN)); + enc28j60_write(MAIPGL, 0x12); + enc28j60_write(MAIPGH, 0x0C); + enc28j60_write(MABBIPG, 0x12); + enc28j60_write(MAMXFLL, (MAX_FRAMELEN & 0xFF)); + enc28j60_write(MAMXFLH, (MAX_FRAMELEN >> 8)); + enc28j60_write(MAADR5, mac_addr[0]); + enc28j60_write(MAADR4, mac_addr[1]); + enc28j60_write(MAADR3, mac_addr[2]); + enc28j60_write(MAADR2, mac_addr[3]); + enc28j60_write(MAADR1, mac_addr[4]); + enc28j60_write(MAADR0, mac_addr[5]); + + enc28j60_set_bank(ECON1); + enc28j60_write_op(BFS, ECON1, ENCRXEN); } -void enc28j60PacketSend(unsigned int len1, unsigned char* packet1, unsigned int len2, unsigned char* packet2) -{ - //Errata: Transmit Logic reset - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST); - enc28j60WriteOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST); - - // Set the write pointer to start of transmit buffer area - enc28j60Write(EWRPTL, TXSTART_INIT&0xff); - enc28j60Write(EWRPTH, TXSTART_INIT>>8); - // Set the TXND pointer to correspond to the packet size given - enc28j60Write(ETXNDL, (TXSTART_INIT+len1+len2)); - enc28j60Write(ETXNDH, (TXSTART_INIT+len1+len2)>>8); - - // write per-packet control byte - enc28j60WriteOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00); - - // copy the packet into the transmit buffer - enc28j60WriteBuffer(len1, packet1); - if(len2>0) enc28j60WriteBuffer(len2, packet2); - - // send the contents of the transmit buffer onto the network - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); +uint16_t enc28j60_recv(uint8_t* buf, uint16_t max_len){ + uint16_t rxstat, len; + + // Return if no data is available + if(enc28j60_read(EPKTCNT) == 0) return 0; + + enc28j60_write(ERDPTL, (next_pkt_ptr & 0xFF)); + enc28j60_write(ERDPTH, (next_pkt_ptr >> 8)); + next_pkt_ptr = enc28j60_read_op(RBM, 0) | ((uint16_t)enc28j60_read_op(RBM, 0) << 8); + len = enc28j60_read_op(RBM, 0) | ((uint16_t)enc28j60_read_op(RBM, 0) << 8); + len -= 4; + rxstat = enc28j60_read_op(RBM, 0) | ((uint16_t)enc28j60_read_op(RBM, 0) << 8); + + // Length sanity check and actual enc28j60_read call + if(len > (max_len - 1)) len = max_len - 1; + if((rxstat & 0x80) == 0) len = 0; + else enc28j60_read_buffer(buf, len); + + // Update next packet pointer + enc28j60_write(ERXRDPTL, (next_pkt_ptr & 0xFF)); + enc28j60_write(ERXRDPTH, (next_pkt_ptr >> 8)); + if(((next_pkt_ptr - 1) < RXSTART_INIT) || ((next_pkt_ptr - 1) > RXSTOP_INIT)){ + enc28j60_write(ERXRDPTL, (RXSTOP_INIT & 0xFF)); + enc28j60_write(ERXRDPTH, (RXSTOP_INIT >> 8)); + } + else{ + enc28j60_write(ERXRDPTL, ((next_pkt_ptr - 1) & 0xFF)); + enc28j60_write(ERXRDPTH, ((next_pkt_ptr - 1) >> 8)); + } + enc28j60_write_op(BFS, ECON2, PKTDEC); + + return len; } -unsigned int enc28j60PacketReceive(unsigned int maxlen, u08* buf) -{ - u16 rxstat; - u16 len; - - // check if a packet has been received and buffered - if( !enc28j60Read(EPKTCNT) ) - return 0; - - // Set the read pointer to the start of the received packet - enc28j60Write(ERDPTL, (NextPacketPtr)); - enc28j60Write(ERDPTH, (NextPacketPtr)>>8); - // read the next packet pointer - NextPacketPtr = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0); - NextPacketPtr |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; - // read the packet length - len = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0); - len |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; - // read the receive status - rxstat = enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0); - rxstat |= enc28j60ReadOp(ENC28J60_READ_BUF_MEM, 0)<<8; - - // limit retrieve length - // (we reduce the MAC-reported length by 4 to remove the CRC) - len = MIN(len, maxlen); - - // copy the packet from the receive buffer - enc28j60ReadBuffer(len, buf); - - // Move the RX read pointer to the start of the next received packet - // This frees the memory we just read out - enc28j60Write(ERXRDPTL, (NextPacketPtr)); - enc28j60Write(ERXRDPTH, (NextPacketPtr)>>8); - - // decrement the packet counter indicate we are done with this packet - enc28j60WriteOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); - - return len; +void enc28j60_send(uint8_t* buf, uint16_t len){ + + // Wait for any current transmission to finish + while(enc28j60_read_op(RCR, ECON1) & TXRTS){ + if(enc28j60_read(EIR) & TXERIF){ + enc28j60_write_op(BFS, ECON1, TXRST); + enc28j60_write_op(BFC, ECON1, TXRST); + } + } + + enc28j60_write(EWRPTL, (TXSTART_INIT & 0xFF)); + enc28j60_write(EWRPTH, (TXSTART_INIT >> 8)); + enc28j60_write(ETXNDL, ((TXSTART_INIT + len) & 0xFF)); + enc28j60_write(ETXNDH, ((TXSTART_INIT + len) >> 8)); + enc28j60_write_op(WBM, 0, 0x00); + enc28j60_write_buffer(buf, len); + enc28j60_write_op(BFS, ECON1, TXRTS); } diff --git a/firmware/octoclock/lib/init.c b/firmware/octoclock/lib/init.c index 827ccb376..8592aa091 100644 --- a/firmware/octoclock/lib/init.c +++ b/firmware/octoclock/lib/init.c @@ -71,7 +71,7 @@ void setup_atmel_io_ports(){ // /pd_cdcd, /sync_code, /ce need to be 1 (disabled) to start // all bits are outputs, except PA7 (gps_lock) and PA3 (MISO_CDCE) are inputs -PORTA = Bits_8(00110010); +PORTA = Bits_8(00100010); DDRA = 1<<DDA6 | 1<<DDA5 | 1<<DDA4 | 1<<DDA2 | 1<<DDA1 | 1<<DDA0; /* @@ -90,8 +90,8 @@ DDRA = 1<<DDA6 | 1<<DDA5 | 1<<DDA4 | 1<<DDA2 | 1<<DDA1 | 1<<DDA0; * */ -PORTB = Bits_8(01100001); // Initial Value is all zeros -DDRB = 1<<DDB2 | 1<<DDB4 | 1<<DDB7; // MOSI is an output; the Not Connected pins are also outputs +PORTB = Bits_8(01100001); // Initial Value is all zeros +DDRB = Bits_8(11110111); // MOSI is an output; the Not Connected pins are also outputs /* * Port C diff --git a/firmware/octoclock/lib/network.c b/firmware/octoclock/lib/network.c index bb49de4f6..22fc2b54b 100644 --- a/firmware/octoclock/lib/network.c +++ b/firmware/octoclock/lib/network.c @@ -27,6 +27,7 @@ #include <debug.h> #include <octoclock.h> +#include <state.h> #include <network.h> #include <net/enc28j60.h> @@ -34,12 +35,14 @@ #include <net/if_arp.h> #include <net/ethertype.h> +#include <util/delay.h> + #include "arp_cache.h" /*********************************************************************** * Constants + Globals **********************************************************************/ -static const size_t out_buff_size = 512; +static const size_t out_buff_size = ETH_BUF_SIZE; static const eth_mac_addr_t BCAST_MAC_ADDR = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; #define MAX_UDP_LISTENERS 10 @@ -139,7 +142,7 @@ send_pkt( //grab an out buffer and pointer //select the output buffer based on type of packet uint8_t *p; - p = buf_out; + p = eth_buf; size_t total_len = 0; //create a list of all buffers to copy @@ -149,7 +152,7 @@ send_pkt( //copy each buffer into the out buffer for (size_t i = 0; i < sizeof(buffs)/sizeof(buffs[0]); i++){ total_len += lens[i]; //use full length (not clipped) - size_t bytes_remaining = out_buff_size - (size_t)(p - (uint8_t*)buf_out); + size_t bytes_remaining = out_buff_size - (size_t)(p - (uint8_t*)eth_buf); if (lens[i] > bytes_remaining) lens[i] = bytes_remaining; memcpy(p, buffs[i], lens[i]); p += lens[i]; @@ -161,7 +164,7 @@ send_pkt( //For some reason, the ENC28J60 won't send the CRC //if you don't tell it to send another byte after //the given packet - enc28j60PacketSend(total_len+1, buf_out, 0, 0); + enc28j60_send(eth_buf, total_len); } static void @@ -333,15 +336,15 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) void handle_eth_packet(size_t recv_len) { - eth_hdr_t *eth_hdr = (eth_hdr_t *)buf_in; + eth_hdr_t *eth_hdr = (eth_hdr_t *)eth_buf; uint16_t ethertype = htons(eth_hdr->ethertype); if (ethertype == ETHERTYPE_ARP){ - struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(buf_in + sizeof(eth_hdr_t)); + struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(eth_buf + sizeof(eth_hdr_t)); handle_arp_packet(arp, recv_len-ETH_HLEN); } else if (ethertype == ETHERTYPE_IPV4){ - struct ip_hdr *ip = (struct ip_hdr *)(buf_in + sizeof(eth_hdr_t)); + struct ip_hdr *ip = (struct ip_hdr *)(eth_buf + sizeof(eth_hdr_t)); if (_IPH_V(ip) != 4 || _IPH_HL(ip) != 5) // ignore pkts w/ bad version or options return; @@ -357,7 +360,7 @@ handle_eth_packet(size_t recv_len) bool is_my_ip = memcmp(&ip->dest, &htonl_local_ip_addr, sizeof(_local_ip_addr)) == 0; if (!is_bcast && !is_my_ip) return; - arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)buf_in)+6)); + arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)eth_buf)+6)); switch (_IPH_PROTO(ip)){ case IP_PROTO_UDP: @@ -381,7 +384,6 @@ handle_eth_packet(size_t recv_len) **********************************************************************/ static bool send_garp = false; -static bool sent_initial_garp = false; static uint32_t num_overflows = 0; // Six overflows is the closest overflow count to one minute. @@ -390,6 +392,7 @@ ISR(TIMER1_OVF_vect){ if(!(num_overflows % 6)) send_garp = true; } +// Send a GARP packet once per minute. static void send_gratuitous_arp(){ send_garp = false; @@ -415,18 +418,9 @@ send_gratuitous_arp(){ // Executed every loop void network_check(void){ - size_t recv_len = enc28j60PacketReceive(512, buf_in); + size_t recv_len = enc28j60_recv(eth_buf, ETH_BUF_SIZE); if(recv_len > 0) handle_eth_packet(recv_len); - /* - * Send a gratuitous ARP packet two seconds after Ethernet - * initialization. - */ - if(!sent_initial_garp && (num_overflows == 0 && TCNT1 > (TIMER1_ONE_SECOND*2))){ - sent_initial_garp = true; - send_garp = true; - } - if(send_garp) send_gratuitous_arp(); } @@ -435,9 +429,10 @@ void network_init(void){ * Read MAC address from EEPROM and initialize Ethernet driver. If EEPROM is blank, * use default MAC address instead. */ + eeprom_busy_wait(); if(eeprom_read_byte(0) == 0xFF){ _MAC_ADDR(_local_mac_addr.addr, 0x00,0x80,0x2F,0x11,0x22,0x33); - _local_ip_addr.addr = default_ip; + _local_ip_addr.addr = _IP(192,168,10,3); using_network_defaults = true; } else{ @@ -446,5 +441,8 @@ void network_init(void){ using_network_defaults = false; } - enc28j60Init((uint8_t*)&_local_mac_addr); + enc28j60_init((uint8_t*)&_local_mac_addr); + init_udp_listeners(); + + send_garp = true; } diff --git a/firmware/octoclock/lib/state.c b/firmware/octoclock/lib/state.c index 0dbcc6ece..26e1b783c 100644 --- a/firmware/octoclock/lib/state.c +++ b/firmware/octoclock/lib/state.c @@ -15,110 +15,80 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <avr/interrupt.h> #include <avr/io.h> +#include <avrlibdefs.h> #include <debug.h> #include <octoclock.h> #include <clkdist.h> #include <state.h> -void led(LEDs which, int turn_it_on) { +// Global state variables +volatile bool g_ext_ref_present = false; +volatile bool g_gps_present = false; +volatile switch_pos_t g_switch_pos = PREFER_INTERNAL; +volatile ref_t g_ref = NO_REF; +void led(led_t which, bool on){ // selects the proper bit uint8_t LED = 0x20 << which; - if(turn_it_on) + if(on) PORTC |= LED; else PORTC &= ~LED; } -void LEDs_Off(void){ - led(Top,false); - led(Middle,false); - led(Bottom,false); +void leds_off(void){ + led(LED_TOP, false); + led(LED_MIDDLE, false); + led(LED_BOTTOM, false); } -void force_internal(void){ - led(Top,true); - led(Middle,false); - led(Bottom,true); +static void force_internal(void){ + led(LED_TOP, true); + led(LED_MIDDLE, false); + led(LED_BOTTOM, true); + // Tell ClkDist chip to use internal signals + cli(); setup_TI_CDCE18005(Primary_GPS); + sei(); - // Set PPS to Primary (1) n.b.: "1" in general means "Internal" for all - // such signals + // Set PPS to internal PORTA |= (1<<PA6); } -void force_external(void){ - led(Top, false); - led(Middle, true); - led(Bottom, true); +static void force_external(void){ + led(LED_TOP, false); + led(LED_MIDDLE, true); + led(LED_BOTTOM, true); + // Tell Clkdist chip to use external signals + cli(); setup_TI_CDCE18005(Secondary_Ext); + sei(); - // Set PPS to External + // Set PPS to external PORTA &= ~(1<<PA6); } void prefer_internal(void){ - // if internal is NOT OK, then force external - if(global_gps_present) + // If internal is NOT OK, then force external + if(g_gps_present) force_internal(); - else if(global_ext_ref_is_present) + else if(g_ext_ref_present) force_external(); else - LEDs_Off(); + leds_off(); } void prefer_external(void){ - // if external is NOT OK, then force internal - if(global_ext_ref_is_present) + // If external is NOT OK, then force internal + if(g_ext_ref_present) force_external(); - else if(global_gps_present) + else if(g_gps_present) force_internal(); else - LEDs_Off(); -} - -static uint8_t prev_PE7 = 0; -static uint32_t timer0_num_overflows = 0; - -ISR(TIMER0_OVF_vect){ - global_gps_present = (PIND & (1<<DDD4)); - - // Every ~1/10 second - if(!(timer0_num_overflows % 610)){ - prev_PE7 = (PINE & (1<<DDE7)); - - if(get_switch_pos() == UP) prefer_internal(); - else prefer_external(); - - global_ext_ref_is_present = false; - } - - if(!global_ext_ref_is_present){ - global_ext_ref_is_present = (prev_PE7 != (PINE & (1<<DDE7))); - } - - timer0_num_overflows++; -} - -ref_t which_ref(void){ - if(!global_gps_present && !global_ext_ref_is_present) global_which_ref = NO_REF; - else if(global_gps_present && !global_ext_ref_is_present) global_which_ref = INTERNAL; - else if(!global_gps_present && global_ext_ref_is_present) global_which_ref = EXTERNAL; - else global_which_ref = (get_switch_pos() == UP) ? INTERNAL : EXTERNAL; - - return global_which_ref; -} - -switch_pos_t get_switch_pos(void){ - uint8_t portC = PINC; - - // UP is prefer internal, - // DOWN is prefer external - return (portC & (1<<DDC1)) ? DOWN : UP; + leds_off(); } diff --git a/firmware/octoclock/lib/udp_handlers.c b/firmware/octoclock/lib/udp_handlers.c index 1f20112c9..49b9b8023 100644 --- a/firmware/octoclock/lib/udp_handlers.c +++ b/firmware/octoclock/lib/udp_handlers.c @@ -36,7 +36,7 @@ void handle_udp_ctrl_packet( pkt_out.proto_ver = OCTOCLOCK_FW_COMPAT_NUM; pkt_out.sequence = pkt_in->sequence; - //If the firmware is incompatible, only respond to queries + // If the firmware is incompatible, only respond to queries if(pkt_in->code == OCTOCLOCK_QUERY_CMD){ pkt_out.code = OCTOCLOCK_QUERY_ACK; pkt_out.len = 0; @@ -50,44 +50,43 @@ void handle_udp_ctrl_packet( octoclock_fw_eeprom_t *eeprom_info = (octoclock_fw_eeprom_t*)pkt_out.data; - //Read values from EEPROM into packet + // Read values from EEPROM into packet + eeprom_busy_wait(); eeprom_read_block(eeprom_info, 0, sizeof(octoclock_fw_eeprom_t)); - //If EEPROM network fields are not fully populated, copy defaults + // If EEPROM network fields are not fully populated, copy defaults if(using_network_defaults){ _MAC_ADDR(eeprom_info->mac_addr, 0x00,0x80,0x2F,0x11,0x22,0x33); - eeprom_info->ip_addr = default_ip; - eeprom_info->dr_addr = default_dr; - eeprom_info->netmask = default_netmask; + eeprom_info->ip_addr = _IP(192,168,10,3); + eeprom_info->dr_addr = _IP(192,168,10,1); + eeprom_info->netmask = _IP(255,255,255,0); } - //Check if strings or revision is empty - if(eeprom_info->serial[0] == 0xFF) memset(eeprom_info->serial, 0, 10); - if(eeprom_info->name[0] == 0xFF) memset(eeprom_info->name, 0, 10); + // Check if strings or revision is empty if(eeprom_info->revision == 0xFF) eeprom_info->revision = 0; break; case BURN_EEPROM_CMD:{ - //Confirm length of data + // Confirm length of data if(pkt_in->len != sizeof(octoclock_fw_eeprom_t)){ pkt_out.code = BURN_EEPROM_FAILURE_ACK; break; } /* - * In all cases, a full octoclock_fw_eeprom_t is written to lower the overall - * number of writes due to this EEPROM's smaller amount of safe writes. * It is up to the host to make sure that the values that should be * preserved are present in the octoclock_fw_eeprom_t struct. */ const octoclock_fw_eeprom_t *eeprom_pkt = (octoclock_fw_eeprom_t*)pkt_in->data; pkt_out.len = 0; - //Write EEPROM data from packet + // Write EEPROM data from packet + eeprom_busy_wait(); eeprom_write_block(eeprom_pkt, 0, sizeof(octoclock_fw_eeprom_t)); - //Read back and compare to packet to confirm successful write + // Read back and compare to packet to confirm successful write uint8_t eeprom_contents[sizeof(octoclock_fw_eeprom_t)]; + eeprom_busy_wait(); eeprom_read_block(eeprom_contents, 0, sizeof(octoclock_fw_eeprom_t)); uint8_t n = memcmp(eeprom_contents, eeprom_pkt, sizeof(octoclock_fw_eeprom_t)); pkt_out.code = n ? BURN_EEPROM_FAILURE_ACK @@ -99,12 +98,12 @@ void handle_udp_ctrl_packet( pkt_out.code = SEND_STATE_ACK; pkt_out.len = sizeof(octoclock_state_t); - //Populate octoclock_state_t fields + // Populate octoclock_state_t fields octoclock_state_t *state = (octoclock_state_t*)pkt_out.data; - state->external_detected = global_ext_ref_is_present ? 1 : 0; - state->gps_detected = (PIND & _BV(DDD4)) ? 1 : 0; - state->which_ref = (uint8_t)which_ref(); - state->switch_pos = (uint8_t)get_switch_pos(); + state->external_detected = g_ext_ref_present ? 1 : 0; + state->gps_detected = g_gps_present ? 1 : 0; + state->which_ref = (uint8_t)g_ref; + state->switch_pos = (uint8_t)g_switch_pos; break; case RESET_CMD: diff --git a/firmware/octoclock/lib/usart.c b/firmware/octoclock/lib/usart.c index 3620ac5e9..a267e43c6 100644 --- a/firmware/octoclock/lib/usart.c +++ b/firmware/octoclock/lib/usart.c @@ -34,16 +34,8 @@ char usart_getc(void){ return UDR1; } -char usart_getc_noblock(void){ - return ((UCSR1A & (1 << RXC))) ? UDR1 : -1; -} - void usart_putc(char ch){ while((UCSR1A & (1 << UDRE1)) == 0); UDR1 = ch; } - -void usart_putc_nowait(char ch){ - if((UCSR1A & (1 << UDRE1)) != 0) UDR1 = ch; -} diff --git a/firmware/octoclock/octoclock_r4/CMakeLists.txt b/firmware/octoclock/octoclock_r4/CMakeLists.txt index c3559d8d4..9223721c8 100644 --- a/firmware/octoclock/octoclock_r4/CMakeLists.txt +++ b/firmware/octoclock/octoclock_r4/CMakeLists.txt @@ -43,7 +43,7 @@ add_custom_target( ) add_custom_target( upload_r4 - ${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x81:m -U lfuse:w:0xFF:m -U flash:w:octoclock_r4_fw.hex:i + ${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x81:m -U lfuse:w:0xEF:m -U flash:w:octoclock_r4_fw.hex:i WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS octoclock_r4_fw_hex COMMENT "Uploading OctoClock firmware to device with ${PROGRAMMER}" diff --git a/firmware/octoclock/octoclock_r4/octoclock_r4_main.c b/firmware/octoclock/octoclock_r4/octoclock_r4_main.c index 5e8e6d09b..b1df34195 100644 --- a/firmware/octoclock/octoclock_r4/octoclock_r4_main.c +++ b/firmware/octoclock/octoclock_r4/octoclock_r4_main.c @@ -36,7 +36,7 @@ * JTAGEN = [X] * SPIEN = [X] * EESAVE = [X] - * BOOTSZ = 4096W_F000 + * BOOTSZ = 4095W_F000 * BOOTRST = [ ] * CKOPT = [X] * BODLEVEL = 2V7 @@ -49,57 +49,165 @@ * */ +#include <stdlib.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <avr/eeprom.h> +#include <avr/interrupt.h> #include <avr/io.h> +#include <avrlibdefs.h> #include <octoclock.h> -#include <clkdist.h> #include <debug.h> +#include <clkdist.h> #include <state.h> #include <network.h> #include <usart.h> -#include <gpsdo.h> -#include <net/enc28j60.h> #include <net/udp_handlers.h> +/* + * Timer 3 (16-bit) + * * Set input capture trigger to rising edge + * * Set prescaler to 1 + * * Enable overflow interrupt + * * Set timer to 0 + */ +#define TIMER3_INIT() TCCR3B = (1 << ICES3) | (1 << CS30); \ + ETIMSK |= (1 << TOIE3); \ + TCNT3 = 0; \ + ICR3 = 0; + +/* + * We use TIMER3 as a watchdog timer for external reference + * detection. Once a signal is detected, we allow for five + * timer overflows (~26 ms) without another signal before + * deciding that there is no external reference connected. + */ +#define EXT_REF_TIMEOUT 5 + +static volatile uint16_t num_overflows = 0; +static uint16_t current_num_overflows = 0; +static uint16_t prev_num_overflows = 0; +static uint16_t current_ICR3 = 0; +static uint16_t prev_ICR3 = 0; +static ref_t prev_ref = NO_REF; +static switch_pos_t prev_switch_pos = PREFER_EXTERNAL; +bool top = false; + +ISR(TIMER3_OVF_vect){ + num_overflows++; +} + /******************************************************************************* * Main Routine *******************************************************************************/ int main(void){ - asm("cli"); + /* + * Initializations + */ + cli(); + // Make sure interrupts belong to us + MCUCR = (1<<IVCE); + MCUCR = 0; + + // Initialize global variables + g_ext_ref_present = false; + g_gps_present = false; + g_switch_pos = PREFER_INTERNAL; + g_ref = NO_REF; + + // Atmega128 setup_atmel_io_ports(); - network_init(); - #ifndef DEBUG - asm("sei"); - #endif + // Reset ClkDist chip + reset_TI_CDCE18005(); - init_udp_listeners(); - register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet); + // GPSDO communication + usart_init(); + + // Ethernet stack + network_init(); + register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet); register_udp_listener(OCTOCLOCK_UDP_GPSDO_PORT, handle_udp_gpsdo_packet); - DEBUG_INIT(); // Does nothing when not in debug mode - DEBUG_LOG(" "); //Force a newline between runs - usart_init(); + // Timers + TIMER1_INIT(); // Network + TIMER3_INIT(); // External reference check + + // Debug (does nothing when not in debug mode) + DEBUG_INIT(); + DEBUG_LOG(" "); // Force a newline between runs + + leds_off(); + + sei(); + + // Check if GPS present (should only need to happen once) + g_gps_present = (PIND & (1<<DDD4)); + + // State of previous iteration + prev_ref = NO_REF; + prev_switch_pos = PREFER_EXTERNAL; + cli(); + prev_ICR3 = ICR3; + sei(); + prev_num_overflows = 0; + + /* + * Main loop + */ + while(true){ + // Check switch position + g_switch_pos = (PINC & (1<<DDC1)) ? PREFER_EXTERNAL : PREFER_INTERNAL; + + /* + * Check input capture pin for external reference detection. + * + * 16-bit reads could be corrupted during an interrupt, so + * disable interrupts for safety. + */ + cli(); + current_ICR3 = ICR3; + current_num_overflows = num_overflows; + sei(); + + // Signal detected, reset timer + if(current_ICR3 != prev_ICR3){ + cli(); + TCNT3 = 0; + num_overflows = 0; + sei(); + g_ext_ref_present = true; + } + + // Timeout, no external reference detected + if(current_num_overflows >= EXT_REF_TIMEOUT){ + g_ext_ref_present = false; + } - //Set initial ClkDist and front panel settings - led(Middle,true); - setup_TI_CDCE18005(Primary_GPS); // 10 MHz from Internal Source + // Determine and set reference based on state + if(!g_gps_present && !g_ext_ref_present) g_ref = NO_REF; + else if(g_gps_present && !g_ext_ref_present) g_ref = INTERNAL; + else if(!g_gps_present && g_ext_ref_present) g_ref = EXTERNAL; + else g_ref = (g_switch_pos == PREFER_INTERNAL) ? INTERNAL : EXTERNAL; - led(Top,true); - PORTA |= (1<<PA6); // PPS from Internal source + if((g_ref != prev_ref) || (g_switch_pos != prev_switch_pos)){ + if(g_switch_pos == PREFER_INTERNAL) prefer_internal(); + else prefer_external(); + } - TIMER0_INIT(); - TIMER1_INIT(); + // Record this iteration's state + prev_ref = g_ref; + prev_switch_pos = g_switch_pos; + prev_ICR3 = current_ICR3; + prev_num_overflows = current_num_overflows; - while(true) { + // Handle incoming Ethernet packets network_check(); } } diff --git a/firmware/usrp3/CMakeLists.txt b/firmware/usrp3/CMakeLists.txt index c25adb68a..f71b79b0c 100644 --- a/firmware/usrp3/CMakeLists.txt +++ b/firmware/usrp3/CMakeLists.txt @@ -68,6 +68,20 @@ FIND_PROGRAM(OBJDUMP zpu-elf-objdump) FIND_PROGRAM(HEXDUMP hexdump) ######################################################################## +# Firmware tracing support +######################################################################## +# Look at include/trace.h to see what the different trace levels map to. +SET(TRACE_LEVEL "0" CACHE STRING "Firmware Trace Level") #0 by default +OPTION(TRACE_LEVEL "Firmware Trace Level" "") +IF(TRACE_LEVEL) + #If TRACE_LEVEL == 0, don't define UHD_FW_TRACE_LEVEL so that the C + #code can easily detect if tracing is requested + IF(${TRACE_LEVEL} GREATER 0) + ADD_DEFINITIONS(-DUHD_FW_TRACE_LEVEL=${TRACE_LEVEL}) + ENDIF(${TRACE_LEVEL} GREATER 0) +ENDIF(TRACE_LEVEL) + +######################################################################## # helper functions to build output formats ######################################################################## SET(GEN_OUTPUTS_BIN_SIZE "bin_size_not_set") #set before calling diff --git a/firmware/usrp3/include/ethernet.h b/firmware/usrp3/include/ethernet.h index 52f14d05b..a6bacfcd0 100644 --- a/firmware/usrp3/include/ethernet.h +++ b/firmware/usrp3/include/ethernet.h @@ -31,7 +31,7 @@ typedef void (*ethernet_link_changed_callback_t)(int ethnum, int speed); /*! * \brief one time call to initialize ethernet */ -void xge_ethernet_init(const uint32_t eth); +void ethernet_init(const uint32_t eth); /*! * \brief Return number of ethernet interfaces @@ -44,8 +44,7 @@ void dump_mdio_regs(const uint8_t eth, uint32_t mdio_port); /*! * \brief Test status of SFP+ modules */ -void -xge_poll_sfpp_status(const uint32_t eth); +void poll_sfpp_status(const uint32_t eth); //! get the link status of eth (true for link up) bool ethernet_get_link_up(const uint32_t eth); diff --git a/firmware/usrp3/include/trace.h b/firmware/usrp3/include/trace.h new file mode 100644 index 000000000..0daa231fe --- /dev/null +++ b/firmware/usrp3/include/trace.h @@ -0,0 +1,82 @@ +// +// Copyright 2015 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that 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. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_TRACE_H +#define INCLUDED_TRACE_H + +#include <stdint.h> +#include <stdbool.h> +#include <printf.h> + +/* + * Enables basic conditional tracing support + * If UHD_FW_TRACE_LEVEL is defined, all messages + * with a verbosity >= UHD_FW_TRACE_LEVEL will be + * printed. + * + * An alternate way of defining the level is the "TRACE_LEVEL" + * variable in cmake. (eg. -DTRACE_LEVEL=13). + */ +//#define UHD_FW_TRACE_LEVEL 13 + +typedef enum +{ + /* 0-9: Use for performance/restricted debugging */ + ERROR = 10, + WARN = 11, + INFO = 12, + /* 13-19: Use for general debugging */ + DEBUG = 20, //Verbose! +} trace_level_t; + +static inline int _trace_typecheck_conv(trace_level_t lvl) { + return (int)lvl; +} + +#define UHD_FW_PRINTF(...) printf(__VA_ARGS__) +#define UHD_FW_BEAUTIFY_LVL(lvl) "[" #lvl "] " + +/* + * UHD_FW_TRACE(<log level>, <message>) + * - Simple trace. Print the messages with the log level as the prefix and \n at the end + * + * UHD_FW_TRACE_FSTR(<log level>, <format string>, <args>) + * - Trace format string with the log level as the prefix and \n at the end + * + * UHD_FW_TRACE_SHORT(<log level>, <message>) + * - Simple trace. Print the messages without the log level prefix or \n at the end + * + * UHD_FW_TRACE_FSTR_SHORT(<log level>, <format string>, <args>) + * - Trace format string without the log level prefix or \n at the end + */ +#ifdef UHD_FW_TRACE_LEVEL + #define UHD_FW_TRACE(lvl, fmt) \ + if (UHD_FW_TRACE_LEVEL >= _trace_typecheck_conv(lvl)) UHD_FW_PRINTF(UHD_FW_BEAUTIFY_LVL(lvl) fmt "\r\n"); + #define UHD_FW_TRACE_FSTR(lvl, fmt, ...) \ + if (UHD_FW_TRACE_LEVEL >= _trace_typecheck_conv(lvl)) UHD_FW_PRINTF(UHD_FW_BEAUTIFY_LVL(lvl) fmt "\r\n", __VA_ARGS__); + #define UHD_FW_TRACE_SHORT(lvl, fmt) \ + if (UHD_FW_TRACE_LEVEL >= _trace_typecheck_conv(lvl)) UHD_FW_PRINTF(fmt); + #define UHD_FW_TRACE_FSTR_SHORT(lvl, fmt, ...) \ + if (UHD_FW_TRACE_LEVEL >= _trace_typecheck_conv(lvl)) UHD_FW_PRINTF(fmt, __VA_ARGS__); +#else + #define UHD_FW_TRACE(lvl, fmt) ; + #define UHD_FW_TRACE_FSTR(lvl, fmt, ...) ; + #define UHD_FW_TRACE_SHORT(lvl, fmt) ; + #define UHD_FW_TRACE_FSTR_SHORT(lvl, fmt, ...) ; +#endif + +#endif /* INCLUDED_TRACE_H */ diff --git a/firmware/usrp3/lib/ethernet.c b/firmware/usrp3/lib/ethernet.c index 7a86980c7..91efbfe1d 100644 --- a/firmware/usrp3/lib/ethernet.c +++ b/firmware/usrp3/lib/ethernet.c @@ -22,7 +22,7 @@ #include "../x300/x300_defs.h" #include "ethernet.h" #include "mdelay.h" -#include "printf.h" +#include <trace.h> #include "wb_i2c.h" #include "wb_utils.h" //#include "memory_map.h" @@ -225,7 +225,7 @@ xge_read_sfpp_type(const uint32_t base, const uint32_t delay_ms) x = xge_i2c_rd(base, MODULE_DEV_ADDR, 3); // I2C Error? if (x < 0) { - printf("DEBUG: I2C error in SFPP_TYPE.\n"); + UHD_FW_TRACE(ERROR, "I2C error in SFPP_TYPE."); return x; } // Decode module type. These registers and values are defined in SFF-8472 @@ -235,55 +235,55 @@ xge_read_sfpp_type(const uint32_t base, const uint32_t delay_ms) } if (x & 0x10) { - printf("DEBUG: SFFP_TYPE_SR.\n"); + UHD_FW_TRACE(DEBUG, "SFFP_TYPE_SR."); return SFFP_TYPE_SR; } if (x & 0x20) { - printf("DEBUG: SFFP_TYPE_LR.\n"); + UHD_FW_TRACE(DEBUG, "SFFP_TYPE_LR."); return SFFP_TYPE_LR; } if (x & 0x40) { - printf("DEBUG: SFFP_TYPE_LRM.\n"); + UHD_FW_TRACE(DEBUG, "SFFP_TYPE_LRM."); return SFFP_TYPE_LRM; } // Search for legacy 1000-Base SFP types x = xge_i2c_rd(base, MODULE_DEV_ADDR, 0x6); if (x < 0) { - printf("DEBUG: I2C error in SFPP_TYPE.\n"); + UHD_FW_TRACE(ERROR, "I2C error in SFPP_TYPE."); return x; } if (x & 0x01) { - printf("DEBUG: SFFP_TYPE_1000BASE_SX.\n"); + UHD_FW_TRACE(DEBUG, "SFFP_TYPE_1000BASE_SX."); return SFFP_TYPE_1000BASE_SX; } if (x & 0x02) { - printf("DEBUG: SFFP_TYPE_1000BASE_LX.\n"); + UHD_FW_TRACE(DEBUG, "SFFP_TYPE_1000BASE_LX."); return SFFP_TYPE_1000BASE_LX; } if (x & 0x08) { - printf("DEBUG: SFFP_TYPE_1000BASE_T.\n"); + UHD_FW_TRACE(DEBUG, "SFFP_TYPE_1000BASE_T."); return SFFP_TYPE_1000BASE_T; } // Not one of the standard optical types..now try to deduce if it's twinax aka 10GSFP+CU // which is not covered explicitly in SFF-8472 x = xge_i2c_rd(base, MODULE_DEV_ADDR, 8); if (x < 0) { - printf("DEBUG: I2C error in SFPP_TYPE.\n"); + UHD_FW_TRACE(ERROR, "I2C error in SFPP_TYPE."); return x; } if ((x & 4) == 0) // Passive SFP+ cable type goto unknown; // x = xge_i2c_rd(MODULE_DEV_ADDR, 6); -// printf("SFP+ reg6 read as %x\n",x); +// UHD_FW_TRACE(DEBUG, "SFP+ reg6 read as %x",x); // if (x < 0) // return x; // if (x != 0x04) // Returns 1000Base-CX as Compliance code // goto unknown; x = xge_i2c_rd(base, MODULE_DEV_ADDR, 0xA); if (x < 0) { - printf("DEBUG: I2C error in SFPP_TYPE.\n"); + UHD_FW_TRACE(ERROR, "I2C error in SFPP_TYPE."); return x; } if (x & 0x80) { @@ -292,117 +292,124 @@ xge_read_sfpp_type(const uint32_t base, const uint32_t delay_ms) x = xge_i2c_rd(base, MODULE_DEV_ADDR, 0x12); if (x < 0) { - printf("DEBUG: I2C error in SFPP_TYPE.\n"); + UHD_FW_TRACE(ERROR, "I2C error in SFPP_TYPE."); return x; } - printf("DEBUG: TwinAx.\n"); + UHD_FW_TRACE(DEBUG, "TwinAx."); // If cable length support is greater than 10M then pick correct type return x > 10 ? SFFP_TYPE_TWINAX_LONG : SFFP_TYPE_TWINAX; } unknown: - printf("DEBUG: Unknown SFP+ type.\n"); + UHD_FW_TRACE(WARN, "Unknown SFP+ type."); // Not a supported Module type return SFFP_TYPE_UNKNOWN; } - -// Pull reset line low for 100ms then release and wait 100ms -static void -xge_hard_phy_reset(const uint32_t base) +static void xge_mac_init(const uint32_t base) { - wb_poke32(base, 1); - mdelay(100); - wb_poke32(base, 0); - mdelay(100); - + UHD_FW_TRACE(DEBUG, "Begining XGE MAC init sequence."); + xge_regs->config = XGE_TX_ENABLE; } -static void -xge_mac_init(const uint32_t base) +// base is pointer to XGE MAC on Wishbone. +static void xge_phy_init(const uint8_t eth, const uint32_t mdio_port_arg) { - printf("INFO: Begining XGE MAC init sequence.\n"); - xge_regs->config = XGE_TX_ENABLE; + int x; + uint32_t mdio_port = eth==0 ? 1 : mdio_port_arg; + // Read LASI Ctrl register to capture state. + //y = xge_read_mdio(0x9002,XGE_MDIO_DEVICE_PMA,XGE_MDIO_ADDR_PHY_A); + UHD_FW_TRACE(DEBUG, "Begining XGE PHY init sequence."); + // Software reset + x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port); + x = x | (1 << 15); + write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); + while(x&(1<<15)) { + x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port); + } } -// base is pointer to XGE MAC on Wishbone. -static void -xge_phy_init(const uint8_t eth, const uint32_t mdio_port) +void update_eth_state(const uint32_t eth) { - int x; - // Read LASI Ctrl register to capture state. - //y = xge_read_mdio(0x9002,XGE_MDIO_DEVICE_PMA,XGE_MDIO_ADDR_PHY_A); - printf("INFO: Begining XGE PHY init sequence.\n"); - // Software reset - x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port); - x = x | (1 << 15); - write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); - while(x&(1<<15)) - x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port); + const bool old_link_up = links_up[eth]; + const uint32_t status_reg_addr = (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1; + const bool is_10g = (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1); + + uint32_t sfpp_status = wb_peek32(SR_ADDR(RB0_BASE, status_reg_addr)) & 0xFFFF; + if ((sfpp_status & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) { + //SFP+ pin state changed. Reinitialize PHY and MAC + if (is_10g) { + xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); + xge_phy_init(eth ,MDIO_PORT); + } else { + //No-op for 1G + } + + int8_t timeout = 100; + bool link_up = false; + do { + if (is_10g) { + link_up = ((read_mdio(eth, XGE_MDIO_STATUS1,XGE_MDIO_DEVICE_PMA,MDIO_PORT)) & (1 << 2)) != 0; + } else { + link_up = ((wb_peek32(SR_ADDR(RB0_BASE, status_reg_addr)) >> 16) & 0x1) != 0; + } + } while (!link_up && timeout-- > 0); + + links_up[eth] = link_up; + } + else + { + links_up[eth] = false; + } + + if (!old_link_up && links_up[eth]) u3_net_stack_send_arp_request(eth, u3_net_stack_get_ip_addr(eth)); + UHD_FW_TRACE_FSTR(INFO, "The link on eth port %u is %s", eth, links_up[eth]?"up":"down"); } -void -xge_poll_sfpp_status(const uint32_t eth) +void poll_sfpp_status(const uint32_t eth) { - uint32_t x; - // Has MODDET/MODAbS changed since we last looked? - x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); - - if (x & SFPP_STATUS_RXLOS_CHG) - printf("DEBUG: eth%1d RXLOS changed state: %d\n", eth, x & SFPP_STATUS_RXLOS); - if (x & SFPP_STATUS_TXFAULT_CHG) - printf("DEBUG: eth%1d TXFAULT changed state: %d\n", eth,(x & SFPP_STATUS_TXFAULT) >> 1 ); - if (x & SFPP_STATUS_MODABS_CHG) - printf("DEBUG: eth%1d MODABS changed state: %d\n", eth, (x & SFPP_STATUS_MODABS) >> 2); - - if (x & (SFPP_STATUS_RXLOS_CHG|SFPP_STATUS_TXFAULT_CHG|SFPP_STATUS_MODABS_CHG)) - { - if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) + uint32_t x; + // Has MODDET/MODAbS changed since we last looked? + x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); + + if (x & SFPP_STATUS_RXLOS_CHG) + UHD_FW_TRACE_FSTR(DEBUG, "eth%1d RXLOS changed state: %d", eth, (x & SFPP_STATUS_RXLOS)); + if (x & SFPP_STATUS_TXFAULT_CHG) + UHD_FW_TRACE_FSTR(DEBUG, "eth%1d TXFAULT changed state: %d", eth, ((x & SFPP_STATUS_TXFAULT) >> 1)); + if (x & SFPP_STATUS_MODABS_CHG) + UHD_FW_TRACE_FSTR(DEBUG, "eth%1d MODABS changed state: %d", eth, ((x & SFPP_STATUS_MODABS) >> 2)); + + //update the link up status + if ((x & SFPP_STATUS_RXLOS_CHG) || (x & SFPP_STATUS_TXFAULT_CHG) || (x & SFPP_STATUS_MODABS_CHG)) { - if (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1) - { - xge_ethernet_init(eth); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - mdelay(100); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - mdelay(100); - dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); - } + update_eth_state(eth); } - } - if (x & SFPP_STATUS_MODABS_CHG) { - // MODDET has changed state since last checked - if (x & SFPP_STATUS_MODABS) { - // MODDET is high, module currently removed. - printf("INFO: An SFP+ module has been removed from eth port %d.\n", eth); - } else { - // MODDET is low, module currently inserted. - // Return status. - printf("INFO: A new SFP+ module has been inserted into eth port %d.\n", eth); - xge_read_sfpp_type((eth==0) ? I2C0_BASE : I2C2_BASE,1); + if (x & SFPP_STATUS_MODABS_CHG) { + // MODDET has changed state since last checked + if (x & SFPP_STATUS_MODABS) { + // MODDET is high, module currently removed. + UHD_FW_TRACE_FSTR(INFO, "An SFP+ module has been removed from eth port %d.", eth); + } else { + // MODDET is low, module currently inserted. + // Return status. + UHD_FW_TRACE_FSTR(INFO, "A new SFP+ module has been inserted into eth port %d.", eth); + xge_read_sfpp_type((eth==0) ? I2C0_BASE : I2C2_BASE,1); + } } - } - - //update the link up status - const bool old_link_up = links_up[eth]; - links_up[eth] = ((read_mdio(eth, XGE_MDIO_STATUS1,XGE_MDIO_DEVICE_PMA,MDIO_PORT)) & (1 << 2)) != 0; - //The link became up, send a GARP so everyone knows our mac/ip association - if (!old_link_up && links_up[eth]) u3_net_stack_send_arp_request(eth, u3_net_stack_get_ip_addr(eth)); } - -void -xge_ethernet_init(const uint32_t eth) +void ethernet_init(const uint32_t eth) { - xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); - //xge_hard_phy_reset(); - xge_phy_init(eth ,MDIO_PORT); - uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); - printf(" eth%1d SFP initial state: RXLOS: %d TXFAULT: %d MODABS: %d\n", - eth, - x & SFPP_STATUS_RXLOS, - (x & SFPP_STATUS_TXFAULT) >> 1, - (x & SFPP_STATUS_MODABS) >> 2); +#ifdef UHD_FW_TRACE_LEVEL + uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); + UHD_FW_TRACE_FSTR(DEBUG, "eth%1d SFP initial state: RXLOS: %d TXFAULT: %d MODABS: %d", + eth, + (x & SFPP_STATUS_RXLOS), + ((x & SFPP_STATUS_TXFAULT) >> 1), + ((x & SFPP_STATUS_MODABS) >> 2)); +#endif + links_up[eth] = false; + update_eth_state(eth); } // @@ -412,187 +419,179 @@ xge_ethernet_init(const uint32_t eth) void decode_reg(uint32_t address, uint32_t device, uint32_t data) { + UHD_FW_TRACE_FSTR(DEBUG, + "[MDIO Register Dump for Addr=%x, Device=%x]\n- Raw Value = %x", + address, device, data); int x; - printf("Device: "); - printf("%x",device); - printf(" "); switch(address) { case XGE_MDIO_CONTROL1: - printf("CONTROL1: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "CONTROL1: %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { - case 15: printf("Reset,"); break; - case 14: printf("Loopback,"); break; - case 11: printf("Low Power Mode,"); break; - case 5:case 4:case 3:case 2: printf("RESERVED speed value,"); break; - case 0: printf("PMA loopback,"); break; + case 15: UHD_FW_TRACE_SHORT(DEBUG, "Reset,"); break; + case 14: UHD_FW_TRACE_SHORT(DEBUG, "Loopback,"); break; + case 11: UHD_FW_TRACE_SHORT(DEBUG, "Low Power Mode,"); break; + case 5:case 4:case 3:case 2: UHD_FW_TRACE_SHORT(DEBUG, "RESERVED speed value,"); break; + case 0: UHD_FW_TRACE_SHORT(DEBUG, "PMA loopback,"); break; } //else // Bits clear. //switch (x) { - //case 13: case 6: printf(" None 10Gb/s speed set!"); break; + //case 13: case 6: UHD_FW_TRACE_SHORT(DEBUG, " None 10Gb/s speed set!"); break; //} - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_STATUS1: - printf("STATUS1: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "STATUS1: %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { - case 7: printf("Fault Detected,"); break; - case 2: printf("Link is Up,"); break; - case 1: printf("Supports Low Power,"); break; + case 7: UHD_FW_TRACE_SHORT(DEBUG, "Fault Detected,"); break; + case 2: UHD_FW_TRACE_SHORT(DEBUG, "Link is Up,"); break; + case 1: UHD_FW_TRACE_SHORT(DEBUG, "Supports Low Power,"); break; } else // Bits Clear switch(x) { - case 2: printf("Link is Down,"); break; + case 2: UHD_FW_TRACE_SHORT(DEBUG, "Link is Down,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_SPEED: - printf("SPEED ABILITY: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "SPEED ABILITY: %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { case 15:case 14:case 13:case 12:case 11:case 10:case 9: - case 8:case 7:case 6:case 5:case 4:case 3:case 2:case 1: printf("RESERVED bits set!,"); break; - case 0: printf("Capable of 10Gb/s,"); + case 8:case 7:case 6:case 5:case 4:case 3:case 2:case 1: UHD_FW_TRACE_SHORT(DEBUG, "RESERVED bits set!,"); break; + case 0: UHD_FW_TRACE_SHORT(DEBUG, "Capable of 10Gb/s,"); } else // Bits clear. switch(x) { - case 0: printf("Incapable of 10Gb/s,"); break; + case 0: UHD_FW_TRACE_SHORT(DEBUG, "Incapable of 10Gb/s,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_DEVICES1: - printf("DEVICES IN PACKAGE: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "DEVICES IN PACKAGE: %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { - case 7: printf("Auto-Negotiation,"); break; - case 6: printf("TC,"); break; - case 5: printf("DTE XS,"); break; - case 4: printf("PHY XS,"); break; - case 3: printf("PCS,"); break; - case 2: printf("WIS,"); break; - case 1: printf("PMD/PMA,"); break; - case 0: printf("Clause 22 registers,"); break; + case 7: UHD_FW_TRACE_SHORT(DEBUG, "Auto-Negotiation,"); break; + case 6: UHD_FW_TRACE_SHORT(DEBUG, "TC,"); break; + case 5: UHD_FW_TRACE_SHORT(DEBUG, "DTE XS,"); break; + case 4: UHD_FW_TRACE_SHORT(DEBUG, "PHY XS,"); break; + case 3: UHD_FW_TRACE_SHORT(DEBUG, "PCS,"); break; + case 2: UHD_FW_TRACE_SHORT(DEBUG, "WIS,"); break; + case 1: UHD_FW_TRACE_SHORT(DEBUG, "PMD/PMA,"); break; + case 0: UHD_FW_TRACE_SHORT(DEBUG, "Clause 22 registers,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_DEVICES2: - printf("DEVICES IN PACKAGE (cont): "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "DEVICES IN PACKAGE (cont): %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { - case 15: printf("Vendor device 2,"); break; - case 14: printf("Vendor device 1,"); break; - case 13: printf("Clause 22 extension,"); break; + case 15: UHD_FW_TRACE_SHORT(DEBUG, "Vendor device 2,"); break; + case 14: UHD_FW_TRACE_SHORT(DEBUG, "Vendor device 1,"); break; + case 13: UHD_FW_TRACE_SHORT(DEBUG, "Clause 22 extension,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_CONTROL2: - printf("CONTROL2: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "CONTROL2: %x = ", data); // PMA/PMD if (device == XGE_MDIO_DEVICE_PMA) switch((data & 0xf)) { - case 0xF: printf("10BASE-T,"); break; - case 0xE: printf("100BASE-TX,"); break; - case 0xD: printf("1000BASE-KX,"); break; - case 0xC: printf("1000BASE-T,"); break; - case 0xB: printf("10GBASE-KR,"); break; - case 0xA: printf("10GBASE-KX4,"); break; - case 0x9: printf("10GBASE-T,"); break; - case 0x8: printf("10GBASE-LRM,"); break; - case 0x7: printf("10GBASE-SR,"); break; - case 0x6: printf("10GBASE-LR,"); break; - case 0x5: printf("10GBASE-ER,"); break; - case 0x4: printf("10GBASE-LX4,"); break; - // case 0x3: printf("10GBASE-SW,"); break; - // case 0x2: printf("10GBASE-LW,"); break; - // case 0x1: printf("10GBASE-EW,"); break; - case 0x0: printf("10GBASE-CX4,"); break; + case 0xF: UHD_FW_TRACE_SHORT(DEBUG, "10BASE-T,"); break; + case 0xE: UHD_FW_TRACE_SHORT(DEBUG, "100BASE-TX,"); break; + case 0xD: UHD_FW_TRACE_SHORT(DEBUG, "1000BASE-KX,"); break; + case 0xC: UHD_FW_TRACE_SHORT(DEBUG, "1000BASE-T,"); break; + case 0xB: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-KR,"); break; + case 0xA: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-KX4,"); break; + case 0x9: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-T,"); break; + case 0x8: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LRM,"); break; + case 0x7: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-SR,"); break; + case 0x6: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LR,"); break; + case 0x5: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-ER,"); break; + case 0x4: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LX4,"); break; + // case 0x3: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-SW,"); break; + // case 0x2: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LW,"); break; + // case 0x1: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-EW,"); break; + case 0x0: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-CX4,"); break; } else if (device == XGE_MDIO_DEVICE_PCS) // PCS switch((data & 0x3)) { - case 0x3: printf("10GBASE-T PCS,"); break; - case 0x2: printf("10GBASE-W PCS,"); break; - case 0x1: printf("10GBASE-X PCS,"); break; - case 0x0: printf("10GBASE-R PCS,"); break; + case 0x3: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-T PCS,"); break; + case 0x2: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-W PCS,"); break; + case 0x1: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-X PCS,"); break; + case 0x0: UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-R PCS,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_STATUS2: - printf("STATUS2: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "STATUS2: %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { - case 15: if ((data & (1 << 14)) == 0) printf("Device responding,"); break; - case 13: if (device == XGE_MDIO_DEVICE_PMA) printf("Able detect a Tx fault,"); break; - case 12: if (device == XGE_MDIO_DEVICE_PMA) printf("Able detect an Rx fault,"); break; - case 11: printf("Fault on Tx path,"); break; - case 10: printf("Fault on Rx path,"); break; - case 9: if (device == XGE_MDIO_DEVICE_PMA) printf("Extended abilities in Reg1.11,"); break; - case 8: if (device == XGE_MDIO_DEVICE_PMA) printf("Able to disable TX,"); break; - case 7: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-SR,"); break; - case 6: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-LR,"); break; - case 5: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-ER,"); break; - case 4: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-LX4,"); break; - case 3: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-SW,"); break; - case 2: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-LW,"); break; - case 1: if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-EW,"); break; - case 0: if (device == XGE_MDIO_DEVICE_PMA) printf("loopback,"); break; + case 15: if ((data & (1 << 14)) == 0) UHD_FW_TRACE_SHORT(DEBUG, "Device responding,"); break; + case 13: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "Able detect a Tx fault,"); break; + case 12: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "Able detect an Rx fault,"); break; + case 11: UHD_FW_TRACE_SHORT(DEBUG, "Fault on Tx path,"); break; + case 10: UHD_FW_TRACE_SHORT(DEBUG, "Fault on Rx path,"); break; + case 9: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "Extended abilities in Reg1.11,"); break; + case 8: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "Able to disable TX,"); break; + case 7: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-SR,"); break; + case 6: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LR,"); break; + case 5: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-ER,"); break; + case 4: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LX4,"); break; + case 3: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-SW,"); break; + case 2: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-LW,"); break; + case 1: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "10GBASE-EW,"); break; + case 0: if (device == XGE_MDIO_DEVICE_PMA) UHD_FW_TRACE_SHORT(DEBUG, "loopback,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XGE_MDIO_LANESTATUS: - printf("LANE STATUS: "); - printf("%x",data); printf(" "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "LANE STATUS: %x = ", data); for (x=15; x >= 0 ; x--) if ((data & (1 << x)) != 0) // Bits set. switch(x) { - case 12: printf("Lanes aligned,"); break; - case 11: printf("Able to generate test patterns,"); break; - case 3: printf("Lane 3 synced,"); break; - case 2: printf("Lane 2 synced,"); break; - case 1: printf("Lane 1 synced,"); break; - case 0: printf("Lane 0 synced,"); break; + case 12: UHD_FW_TRACE_SHORT(DEBUG, "Lanes aligned,"); break; + case 11: UHD_FW_TRACE_SHORT(DEBUG, "Able to generate test patterns,"); break; + case 3: UHD_FW_TRACE_SHORT(DEBUG, "Lane 3 synced,"); break; + case 2: UHD_FW_TRACE_SHORT(DEBUG, "Lane 2 synced,"); break; + case 1: UHD_FW_TRACE_SHORT(DEBUG, "Lane 1 synced,"); break; + case 0: UHD_FW_TRACE_SHORT(DEBUG, "Lane 0 synced,"); break; } else // Bits clear switch(x) { - case 3: printf("Lane 3 not synced,"); break; - case 2: printf("Lane 2 not synced,"); break; - case 1: printf("Lane 1 not synced,"); break; - case 0: printf("Lane 0 not synced,"); break; + case 3: UHD_FW_TRACE_SHORT(DEBUG, "Lane 3 not synced,"); break; + case 2: UHD_FW_TRACE_SHORT(DEBUG, "Lane 2 not synced,"); break; + case 1: UHD_FW_TRACE_SHORT(DEBUG, "Lane 1 not synced,"); break; + case 0: UHD_FW_TRACE_SHORT(DEBUG, "Lane 0 not synced,"); break; } - printf(" \n"); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); break; case XILINX_CORE_VERSION: - printf("XILINX CORE VERSION: %x ",data); - printf("Version: %d.%d ",(data&0xf000)>>12,(data&0xf00)>>8); - printf("Patch: %d ",(data&0xE)>>1); - if (data&0x1) printf("Evaluation Version of core"); - printf("\n"); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "XILINX CORE VERSION: %x ",data); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "Version: %d.%d ",((data&0xf000)>>12),((data&0xf00)>>8)); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "Patch: %d ",((data&0xE)>>1)); + UHD_FW_TRACE_SHORT(DEBUG, " \n"); + if (data&0x1) UHD_FW_TRACE(WARN, "Evaluation Version of core"); break; default: - printf("Register @ address: "); - printf("%x",address); - printf(" has value: "); - printf("%x\n",data); + UHD_FW_TRACE_SHORT(DEBUG, "Register @ address: "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "%x",address); + UHD_FW_TRACE_SHORT(DEBUG, " has value: "); + UHD_FW_TRACE_FSTR_SHORT(DEBUG, "%x\n",data); break; } } @@ -605,7 +604,6 @@ dump_mdio_regs(const uint8_t eth, uint32_t mdio_port) unsigned int regs_a[9] = {0,1,4,5,6,7,8,32,33}; unsigned int regs_b[10] = {0,1,4,5,6,7,8,10,11,65535}; - printf("\n"); for (y = 0; y < 10; y++) { @@ -621,7 +619,6 @@ dump_mdio_regs(const uint8_t eth, uint32_t mdio_port) decode_reg(regs_a[y],XGE_MDIO_DEVICE_PCS,x); } - printf("\n"); /* for (y = 0; y < 8; y++) */ /* { */ diff --git a/firmware/usrp3/lib/u3_net_stack.c b/firmware/usrp3/lib/u3_net_stack.c index 6b8ef096c..16eb0f9fe 100644 --- a/firmware/usrp3/lib/u3_net_stack.c +++ b/firmware/usrp3/lib/u3_net_stack.c @@ -3,7 +3,7 @@ #include <u3_net_stack.h> #include <string.h> //memcmp -#include <printf.h> +#include <trace.h> #define MAX_NETHS 4 @@ -281,7 +281,7 @@ void u3_net_stack_send_arp_request(const uint8_t ethno, const struct ip_addr *ad static void handle_arp_packet(const uint8_t ethno, const struct arp_eth_ipv4 *p) { - //printf("handle_arp_packet\n"); + UHD_FW_TRACE(DEBUG, "handle_arp_packet"); if (p->ar_hrd != ARPHRD_ETHER || p->ar_pro != ETHERTYPE_IPV4 || p->ar_hln != sizeof(eth_mac_addr_t) @@ -291,7 +291,7 @@ static void handle_arp_packet(const uint8_t ethno, const struct arp_eth_ipv4 *p) //got an arp reply -- injest it into the arp cache if (p->ar_op == ARPOP_REPLY) { - //printf("ARPOP_REPLY\n"); + UHD_FW_TRACE(DEBUG, "ARPOP_REPLY"); struct ip_addr ip_addr; memcpy(&ip_addr, p->ar_sip, sizeof(ip_addr)); eth_mac_addr_t mac_addr; @@ -302,7 +302,7 @@ static void handle_arp_packet(const uint8_t ethno, const struct arp_eth_ipv4 *p) //got an arp request -- reply if its for our address if (p->ar_op == ARPOP_REQUEST) { - //printf("ARPOP_REQUEST\n"); + UHD_FW_TRACE(DEBUG, "ARPOP_REQUEST"); if (memcmp(p->ar_tip, u3_net_stack_get_ip_addr(ethno), sizeof(struct ip_addr)) == 0) { send_arp_reply(ethno, p, u3_net_stack_get_mac_addr(ethno)); @@ -344,7 +344,7 @@ void u3_net_stack_send_udp_pkt( eth_mac_addr_t dst_mac_addr; if (!resolve_ip(dst, &dst_mac_addr)) { - printf("u3_net_stack_send_udp_pkt arp_cache_lookup fail\n"); + UHD_FW_TRACE(WARN, "u3_net_stack_send_udp_pkt arp_cache_lookup fail"); return; } @@ -396,7 +396,7 @@ static void handle_udp_packet( return; } } - printf("Unhandled UDP packet src=%u, dest=%u\n", udp->src, udp->dest); + UHD_FW_TRACE_FSTR(ERROR, "Unhandled UDP packet src=%u, dest=%u", udp->src, udp->dest); //TODO send destination unreachable } @@ -445,7 +445,7 @@ static void handle_icmp_packet( return; } } - printf("Unhandled ICMP packet type=%u\n", icmp->type); + UHD_FW_TRACE_FSTR(ERROR, "Unhandled ICMP packet type=%u", icmp->type); } static void handle_icmp_dur_packet( @@ -484,7 +484,7 @@ void u3_net_stack_send_icmp_pkt( eth_mac_addr_t dst_mac_addr; if (!resolve_ip(dst, &dst_mac_addr)) { - printf("u3_net_stack_send_echo_request arp_cache_lookup fail\n"); + UHD_FW_TRACE(WARN, "u3_net_stack_send_echo_request arp_cache_lookup fail"); return; } @@ -533,17 +533,17 @@ static void handle_eth_packet(const void *buff, const size_t num_bytes) { const padded_eth_hdr_t *eth_hdr = (padded_eth_hdr_t *)buff; const uint8_t *eth_body = ((const uint8_t *)buff) + sizeof(padded_eth_hdr_t); - //printf("handle_eth_packet got ethertype 0x%x\n", (unsigned)eth_hdr->ethertype); + UHD_FW_TRACE_FSTR(DEBUG, "handle_eth_packet got ethertype 0x%x", (unsigned)eth_hdr->ethertype); if (eth_hdr->ethertype == ETHERTYPE_ARP) { - //printf("eth_hdr->ethertype == ETHERTYPE_ARP\n"); + UHD_FW_TRACE(DEBUG, "eth_hdr->ethertype == ETHERTYPE_ARP"); const struct arp_eth_ipv4 *arp = (const struct arp_eth_ipv4 *)eth_body; handle_arp_packet(eth_hdr->ethno, arp); } else if (eth_hdr->ethertype == ETHERTYPE_IPV4) { - //printf("eth_hdr->ethertype == ETHERTYPE_IPV4\n"); + UHD_FW_TRACE(DEBUG, "eth_hdr->ethertype == ETHERTYPE_IPV4"); const struct ip_hdr *ip = (const struct ip_hdr *)eth_body; const uint8_t *ip_body = eth_body + IP_HLEN; @@ -572,7 +572,7 @@ static void handle_eth_packet(const void *buff, const size_t num_bytes) ); } } - else return; // Not ARP or IPV4, ignore + else return; // Not ARP or IPV4, ignore } void u3_net_stack_handle_one(void) @@ -581,7 +581,7 @@ void u3_net_stack_handle_one(void) const void *ptr = wb_pkt_iface64_rx_try_claim(pkt_iface_config, &num_bytes); if (ptr != NULL) { - //printf("u3_net_stack_handle_one got %u bytes\n", (unsigned)num_bytes); + UHD_FW_TRACE_FSTR(DEBUG, "u3_net_stack_handle_one got %u bytes", (unsigned)num_bytes); incr_stat_counts(ptr); handle_eth_packet(ptr, num_bytes); wb_pkt_iface64_rx_release(pkt_iface_config); diff --git a/firmware/usrp3/x300/x300_defs.h b/firmware/usrp3/x300/x300_defs.h index 65c5d5a23..c4011bd12 100644 --- a/firmware/usrp3/x300/x300_defs.h +++ b/firmware/usrp3/x300/x300_defs.h @@ -51,6 +51,7 @@ static const int RB_SPI_RDY = 1; static const int RB_SPI_DATA = 2; static const int RB_ETH_TYPE0 = 4; static const int RB_ETH_TYPE1 = 5; +static const int RB_FPGA_COMPAT = 6; static const int RB_SFPP_STATUS0 = 8; static const int RB_SFPP_STATUS1 = 9; diff --git a/firmware/usrp3/x300/x300_init.c b/firmware/usrp3/x300/x300_init.c index 66fb120f3..ef97412a2 100644 --- a/firmware/usrp3/x300/x300_init.c +++ b/firmware/usrp3/x300/x300_init.c @@ -7,7 +7,7 @@ #include <wb_i2c.h> #include <stdint.h> #include <stdbool.h> -#include <printf.h> +#include <trace.h> #include <wb_pkt_iface64.h> #include <u3_net_stack.h> #include <link_state_route_proto.h> @@ -73,7 +73,6 @@ const void *pick_inited_field(const void *eeprom, const void *def, const size_t static void init_network(void) { pkt_config = wb_pkt_iface64_init(PKT_RAM0_BASE, 0x1ffc); - printf("PKT RAM0 BASE 0x%x\n", (&pkt_config)->base); u3_net_stack_init(&pkt_config); link_state_route_proto_init(); @@ -115,7 +114,9 @@ static void init_network(void) static void putc(void *p, char c) { -#ifdef X300_DEBUG_UART +//If FW_TRACE_LEVEL is defined, then the trace level is set +//to a non-zero number. Turn on the debug UART to enable tracing +#ifdef UHD_FW_TRACE_LEVEL wb_uart_putc(UART1_BASE, c); #endif } @@ -129,7 +130,11 @@ void x300_init(void) //udp_uart_init(UART0_BASE, X300_GPSDO_UDP_PORT); //now we can init the rest with prints - printf("X300 ZPU Init Begin -- CPU CLOCK is %d MHz\n", CPU_CLOCK/1000000); + UHD_FW_TRACE(INFO, "[ZPU Initializing]"); + UHD_FW_TRACE_FSTR(INFO, "-- Firmware Compat Number: %u.%u", (int)X300_FW_COMPAT_MAJOR, (int)X300_FW_COMPAT_MINOR); + uint32_t fpga_compat = wb_peek32(SR_ADDR(SET0_BASE, RB_FPGA_COMPAT)); + UHD_FW_TRACE_FSTR(INFO, "-- FPGA Compat Number: %u.%u", (fpga_compat>>16), (fpga_compat&0xFFFF)); + UHD_FW_TRACE_FSTR(INFO, "-- Clock Frequency: %u MHz", (CPU_CLOCK/1000000)); //i2c rate init wb_i2c_init(I2C0_BASE, CPU_CLOCK); @@ -139,30 +144,26 @@ void x300_init(void) //hold phy in reset wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), SW_RST_PHY); - printf("DEBUG: eth0 is %2dG\n",(wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0))==1) ? 10 : 1); - printf("DEBUG: eth1 is %2dG\n",(wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1))==1) ? 10 : 1); - //setup net stack and eth state machines init_network(); //phy reset release wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), 0); - // For eth interfaces, initialize the PHY's - mdelay(100); - if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0)) == 1) { - xge_ethernet_init(0); - } - if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1)) == 1) { - xge_ethernet_init(1); - } - //print network summary for (uint8_t e = 0; e < ethernet_ninterfaces(); e++) { - printf(" MAC%u: %s\n", (int)e, mac_addr_to_str(u3_net_stack_get_mac_addr(e))); - printf(" IP%u: %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_ip_addr(e))); - printf(" SUBNET%u: %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_subnet(e))); - printf(" BCAST%u: %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_bcast(e))); + uint32_t offset = SR_ADDR(RB0_BASE, ((e==1)?RB_ETH_TYPE1:RB_ETH_TYPE0)); + UHD_FW_TRACE_FSTR(INFO, "Ethernet Port %u:", (int)e); + UHD_FW_TRACE_FSTR(INFO, "-- PHY: %s", ((wb_peek32(offset)==1) ? "10Gbps" : "1Gbps")); + UHD_FW_TRACE_FSTR(INFO, "-- MAC: %s", mac_addr_to_str(u3_net_stack_get_mac_addr(e))); + UHD_FW_TRACE_FSTR(INFO, "-- IP: %s", ip_addr_to_str(u3_net_stack_get_ip_addr(e))); + UHD_FW_TRACE_FSTR(INFO, "-- SUBNET: %s", ip_addr_to_str(u3_net_stack_get_subnet(e))); + UHD_FW_TRACE_FSTR(INFO, "-- BCAST: %s", ip_addr_to_str(u3_net_stack_get_bcast(e))); } + + // For eth interfaces, initialize the PHY's + mdelay(100); + ethernet_init(0); + ethernet_init(1); } diff --git a/firmware/usrp3/x300/x300_main.c b/firmware/usrp3/x300/x300_main.c index d865e1d09..3b812a2c4 100644 --- a/firmware/usrp3/x300/x300_main.c +++ b/firmware/usrp3/x300/x300_main.c @@ -13,7 +13,7 @@ #include <udp_uart.h> #include <u3_net_stack.h> #include <link_state_route_proto.h> -#include <printf.h> +#include <trace.h> #include <string.h> #include <print_addrs.h> @@ -33,7 +33,7 @@ void program_udp_framer( const eth_mac_addr_t *dst_mac = u3_net_stack_arp_cache_lookup(dst_ip); const size_t ethbase = (ethno == 0)? SR_ETHINT0 : SR_ETHINT1; const size_t vdest = (sid >> 16) & 0xff; - printf("handle_udp_prog_framer sid %u vdest %u\n", sid, vdest); + UHD_FW_TRACE_FSTR(INFO, "handle_udp_prog_framer sid %u vdest %u\n", sid, vdest); //setup source framer const eth_mac_addr_t *src_mac = u3_net_stack_get_mac_addr(ethno); @@ -204,7 +204,7 @@ void handle_udp_mtu_detect( if (buff == NULL) { return; } else if (!(request->flags & X300_MTU_DETECT_ECHO_REQUEST)) { - printf("DEBUG: MTU detect got unknown request\n"); + UHD_FW_TRACE(WARN, "MTU detect got unknown request"); reply.flags |= X300_MTU_DETECT_ERROR; } @@ -445,12 +445,12 @@ int main(void) static const uint32_t tick_delta = CPU_CLOCK/1000; if (ticks_passed > tick_delta) { + poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events. + poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events. handle_link_state(); //deal with router table update handle_claim(); //deal with the host claim register update_leds(); //run the link and activity leds garp(); //send periodic garps - xge_poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events. - xge_poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events. last_cronjob = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); } |