mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-31 05:52:55 +08:00
- correct tuh_max3421e_int_api() for nrf52
- hcd_int_disable/enable is software only to reduce interrupt lag
This commit is contained in:
parent
b31924e13e
commit
3740a3287a
@ -31,6 +31,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define _PINNUM(port, pin) ((port)*32 + (pin))
|
||||||
|
|
||||||
// LED
|
// LED
|
||||||
#define LED_PIN 13
|
#define LED_PIN 13
|
||||||
#define LED_STATE_ON 0
|
#define LED_STATE_ON 0
|
||||||
@ -43,6 +45,13 @@
|
|||||||
#define UART_RX_PIN 8
|
#define UART_RX_PIN 8
|
||||||
#define UART_TX_PIN 6
|
#define UART_TX_PIN 6
|
||||||
|
|
||||||
|
// SPI for USB host shield
|
||||||
|
#define MAX3421E_SCK_PIN _PINNUM(1, 15)
|
||||||
|
#define MAX3421E_MOSI_PIN _PINNUM(1, 13)
|
||||||
|
#define MAX3421E_MISO_PIN _PINNUM(1, 14)
|
||||||
|
#define MAX3421E_CS_PIN _PINNUM(1, 12)
|
||||||
|
#define MAX3241E_INTR_PIN _PINNUM(1, 11)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -107,7 +107,12 @@ void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
|||||||
//--------------------------------------------------------------------+
|
//--------------------------------------------------------------------+
|
||||||
void tuh_max3421e_int_api(uint8_t rhport, bool enabled) {
|
void tuh_max3421e_int_api(uint8_t rhport, bool enabled) {
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, enabled);
|
|
||||||
|
if (enabled) {
|
||||||
|
nrfx_gpiote_trigger_enable(MAX3241E_INTR_PIN, true);
|
||||||
|
}else {
|
||||||
|
nrfx_gpiote_trigger_disable(MAX3241E_INTR_PIN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) {
|
void tuh_max3421_spi_cs_api(uint8_t rhport, bool active) {
|
||||||
@ -217,6 +222,19 @@ void board_init(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
|
||||||
|
// MAX3421 need 3.3v signal
|
||||||
|
if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) != UICR_REGOUT0_VOUT_3V3) {
|
||||||
|
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
|
||||||
|
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||||
|
|
||||||
|
NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~UICR_REGOUT0_VOUT_Msk) | UICR_REGOUT0_VOUT_3V3;
|
||||||
|
|
||||||
|
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
|
||||||
|
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
|
||||||
|
|
||||||
|
NVIC_SystemReset();
|
||||||
|
}
|
||||||
|
|
||||||
// manually manage CS
|
// manually manage CS
|
||||||
nrf_gpio_cfg_output(MAX3421E_CS_PIN);
|
nrf_gpio_cfg_output(MAX3421E_CS_PIN);
|
||||||
tuh_max3421_spi_cs_api(0, false);
|
tuh_max3421_spi_cs_api(0, false);
|
||||||
|
@ -184,8 +184,6 @@ typedef struct {
|
|||||||
} max3421_ep_t;
|
} max3421_ep_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
atomic_flag busy; // busy transferring
|
|
||||||
|
|
||||||
// cached register
|
// cached register
|
||||||
uint8_t sndbc;
|
uint8_t sndbc;
|
||||||
uint8_t hirq;
|
uint8_t hirq;
|
||||||
@ -194,7 +192,10 @@ typedef struct {
|
|||||||
uint8_t peraddr;
|
uint8_t peraddr;
|
||||||
uint8_t hxfr;
|
uint8_t hxfr;
|
||||||
|
|
||||||
|
atomic_flag busy; // busy transferring
|
||||||
|
volatile uint8_t intr_disable_count;
|
||||||
volatile uint16_t frame_count;
|
volatile uint16_t frame_count;
|
||||||
|
|
||||||
max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
|
max3421_ep_t ep[CFG_TUH_MAX3421_ENDPOINT_TOTAL]; // [0] is reserved for addr0
|
||||||
|
|
||||||
OSAL_MUTEX_DEF(spi_mutexdef);
|
OSAL_MUTEX_DEF(spi_mutexdef);
|
||||||
@ -220,8 +221,8 @@ void tuh_max3421e_int_api(uint8_t rhport, bool enabled);
|
|||||||
static void max3421_spi_lock(uint8_t rhport, bool in_isr) {
|
static void max3421_spi_lock(uint8_t rhport, bool in_isr) {
|
||||||
// disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr
|
// disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr
|
||||||
if (!in_isr) {
|
if (!in_isr) {
|
||||||
tuh_max3421e_int_api(rhport, false);
|
|
||||||
(void) osal_mutex_lock(_hcd_data.spi_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
(void) osal_mutex_lock(_hcd_data.spi_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||||
|
tuh_max3421e_int_api(rhport, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assert CS
|
// assert CS
|
||||||
@ -294,6 +295,12 @@ static uint8_t reg_read(uint8_t rhport, uint8_t reg, bool in_isr) {
|
|||||||
return ret ? rx_buf[1] : 0;
|
return ret ? rx_buf[1] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr) {
|
||||||
|
reg_write(rhport, HIRQ_ADDR, data, in_isr);
|
||||||
|
// HIRQ write 1 is clear
|
||||||
|
_hcd_data.hirq &= ~data;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
|
static inline void hien_write(uint8_t rhport, uint8_t data, bool in_isr) {
|
||||||
_hcd_data.hien = data;
|
_hcd_data.hien = data;
|
||||||
reg_write(rhport, HIEN_ADDR, data, in_isr);
|
reg_write(rhport, HIEN_ADDR, data, in_isr);
|
||||||
@ -440,13 +447,14 @@ tusb_speed_t handle_connect_irq(uint8_t rhport) {
|
|||||||
bool hcd_init(uint8_t rhport) {
|
bool hcd_init(uint8_t rhport) {
|
||||||
(void) rhport;
|
(void) rhport;
|
||||||
|
|
||||||
hcd_int_disable(rhport);
|
tuh_max3421e_int_api(rhport, false);
|
||||||
tuh_max3421_spi_cs_api(rhport, false);
|
tuh_max3421_spi_cs_api(rhport, false);
|
||||||
|
|
||||||
TU_LOG2_INT(sizeof(max3421_ep_t));
|
TU_LOG2_INT(sizeof(max3421_ep_t));
|
||||||
TU_LOG2_INT(sizeof(max3421_data_t));
|
TU_LOG2_INT(sizeof(max3421_data_t));
|
||||||
|
|
||||||
tu_memclr(&_hcd_data, sizeof(_hcd_data));
|
tu_memclr(&_hcd_data, sizeof(_hcd_data));
|
||||||
|
_hcd_data.peraddr = 0xff; // invalid
|
||||||
|
|
||||||
#if OSAL_MUTEX_REQUIRED
|
#if OSAL_MUTEX_REQUIRED
|
||||||
_hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
|
_hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
|
||||||
@ -469,11 +477,13 @@ bool hcd_init(uint8_t rhport) {
|
|||||||
reg_write(rhport, HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST, false);
|
reg_write(rhport, HCTL_ADDR, HCTL_BUSRST | HCTL_FRMRST, false);
|
||||||
|
|
||||||
// clear all previously pending IRQ
|
// clear all previously pending IRQ
|
||||||
reg_write(rhport, HIRQ_ADDR, 0xff, false);
|
hirq_write(rhport, 0xff, false);
|
||||||
|
|
||||||
// Enable IRQ
|
// Enable IRQ
|
||||||
hien_write(rhport, DEFAULT_HIEN, false);
|
hien_write(rhport, DEFAULT_HIEN, false);
|
||||||
|
|
||||||
|
tuh_max3421e_int_api(rhport, true);
|
||||||
|
|
||||||
// Enable Interrupt pin
|
// Enable Interrupt pin
|
||||||
reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false);
|
reg_write(rhport, CPUCTL_ADDR, CPUCTL_IE, false);
|
||||||
|
|
||||||
@ -481,13 +491,21 @@ bool hcd_init(uint8_t rhport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable USB interrupt
|
// Enable USB interrupt
|
||||||
|
// Not actually enable GPIO interrupt, just set variable to prevent handler to process
|
||||||
void hcd_int_enable (uint8_t rhport) {
|
void hcd_int_enable (uint8_t rhport) {
|
||||||
tuh_max3421e_int_api(rhport, true);
|
(void) rhport;
|
||||||
|
// tuh_max3421e_int_api(rhport, true);
|
||||||
|
if (_hcd_data.intr_disable_count) {
|
||||||
|
_hcd_data.intr_disable_count--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable USB interrupt
|
// Disable USB interrupt
|
||||||
|
// Not actually disable GPIO interrupt, just set variable to prevent handler to process
|
||||||
void hcd_int_disable(uint8_t rhport) {
|
void hcd_int_disable(uint8_t rhport) {
|
||||||
tuh_max3421e_int_api(rhport, false);
|
(void) rhport;
|
||||||
|
//tuh_max3421e_int_api(rhport, false);
|
||||||
|
_hcd_data.intr_disable_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get frame number (1ms)
|
// Get frame number (1ms)
|
||||||
@ -521,7 +539,7 @@ void hcd_port_reset_end(uint8_t rhport) {
|
|||||||
reg_write(rhport, HCTL_ADDR, 0, false);
|
reg_write(rhport, HCTL_ADDR, 0, false);
|
||||||
|
|
||||||
// Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset
|
// Bus reset will also trigger CONDET IRQ, clear and re-enable it after reset
|
||||||
reg_write(rhport, HIRQ_ADDR, HIRQ_CONDET_IRQ, false);
|
hirq_write(rhport, HIRQ_CONDET_IRQ, false);
|
||||||
hien_write(rhport, DEFAULT_HIEN, false);
|
hien_write(rhport, DEFAULT_HIEN, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,19 +590,23 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t daddr, tusb_desc_endpoint_t const * e
|
|||||||
void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
||||||
// Page 12: Programming BULK-OUT Transfers
|
// Page 12: Programming BULK-OUT Transfers
|
||||||
// TODO double buffered
|
// TODO double buffered
|
||||||
if (switch_ep) {
|
|
||||||
peraddr_write(rhport, ep->daddr, in_isr);
|
|
||||||
|
|
||||||
uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0);
|
|
||||||
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0);
|
uint8_t hxfr = ep->ep_num | HXFR_OUT_NIN | (ep->is_iso ? HXFR_ISO : 0);
|
||||||
|
|
||||||
if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) {
|
if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) {
|
||||||
// Control ZLP status use HS
|
// Control ZLP status use HS
|
||||||
hxfr |= HXFR_HS;
|
hxfr |= HXFR_HS;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (switch_ep) {
|
||||||
|
peraddr_write(rhport, ep->daddr, in_isr);
|
||||||
|
|
||||||
|
if ( 0 == (hxfr & HXFR_HS) ) {
|
||||||
|
uint8_t const hctl = (ep->data_toggle ? HCTL_SNDTOG1 : HCTL_SNDTOG0);
|
||||||
|
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( 0 == (hxfr & HXFR_HS) ) {
|
||||||
uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size);
|
uint8_t const xact_len = (uint8_t) tu_min16(ep->total_len - ep->xferred_len, ep->packet_size);
|
||||||
TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,);
|
TU_ASSERT(_hcd_data.hirq & HIRQ_SNDBAV_IRQ,);
|
||||||
if (xact_len) {
|
if (xact_len) {
|
||||||
@ -598,12 +620,6 @@ void xact_out(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
|||||||
|
|
||||||
void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
||||||
// Page 13: Programming BULK-IN Transfers
|
// Page 13: Programming BULK-IN Transfers
|
||||||
if (switch_ep) {
|
|
||||||
peraddr_write(rhport, ep->daddr, in_isr);
|
|
||||||
|
|
||||||
uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0);
|
|
||||||
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0);
|
uint8_t hxfr = ep->ep_num | (ep->is_iso ? HXFR_ISO : 0);
|
||||||
if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) {
|
if (ep->ep_num == 0 && (ep->buf == NULL || ep->total_len == 0)) {
|
||||||
@ -611,6 +627,15 @@ void xact_in(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool in_isr) {
|
|||||||
hxfr |= HXFR_HS;
|
hxfr |= HXFR_HS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (switch_ep) {
|
||||||
|
peraddr_write(rhport, ep->daddr, in_isr);
|
||||||
|
|
||||||
|
if ( 0 == (hxfr & HXFR_HS) ) {
|
||||||
|
uint8_t const hctl = (ep->data_toggle ? HCTL_RCVTOG1 : HCTL_RCVTOG0);
|
||||||
|
reg_write(rhport, HCTL_ADDR, hctl, in_isr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hxfr_write(rhport, hxfr, in_isr);
|
hxfr_write(rhport, hxfr, in_isr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,7 +746,7 @@ static void handle_xfer_done(uint8_t rhport) {
|
|||||||
|
|
||||||
xfer_result_t xfer_result;
|
xfer_result_t xfer_result;
|
||||||
|
|
||||||
//TU_LOG3("HRSL: %02X\r\n", hrsl);
|
// TU_LOG3("HRSL: %02X\r\n", hrsl);
|
||||||
switch(hresult) {
|
switch(hresult) {
|
||||||
case HRSL_SUCCESS:
|
case HRSL_SUCCESS:
|
||||||
xfer_result = XFER_RESULT_SUCCESS;
|
xfer_result = XFER_RESULT_SUCCESS;
|
||||||
@ -821,13 +846,20 @@ void print_hirq(uint8_t hirq) {
|
|||||||
void hcd_int_handler(uint8_t rhport) {
|
void hcd_int_handler(uint8_t rhport) {
|
||||||
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true) & _hcd_data.hien;
|
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true) & _hcd_data.hien;
|
||||||
if (!hirq) return;
|
if (!hirq) return;
|
||||||
|
|
||||||
// print_hirq(hirq);
|
// print_hirq(hirq);
|
||||||
|
|
||||||
if (hirq & HIRQ_FRAME_IRQ) {
|
if (hirq & HIRQ_FRAME_IRQ) {
|
||||||
_hcd_data.frame_count++;
|
_hcd_data.frame_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interrupt is disabled, only ack FRAME IRQ and skip the rest
|
||||||
|
if (_hcd_data.intr_disable_count) {
|
||||||
|
if (hirq & HIRQ_FRAME_IRQ) {
|
||||||
|
hirq_write(rhport, HIRQ_FRAME_IRQ, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (hirq & HIRQ_CONDET_IRQ) {
|
if (hirq & HIRQ_CONDET_IRQ) {
|
||||||
tusb_speed_t speed = handle_connect_irq(rhport);
|
tusb_speed_t speed = handle_connect_irq(rhport);
|
||||||
|
|
||||||
@ -861,7 +893,7 @@ void hcd_int_handler(uint8_t rhport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ack RCVDVAV IRQ
|
// ack RCVDVAV IRQ
|
||||||
reg_write(rhport, HIRQ_ADDR, HIRQ_RCVDAV_IRQ, true);
|
hirq_write(rhport, HIRQ_RCVDAV_IRQ, true);
|
||||||
hirq = reg_read(rhport, HIRQ_ADDR, true);
|
hirq = reg_read(rhport, HIRQ_ADDR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,7 +903,7 @@ void hcd_int_handler(uint8_t rhport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( hirq & HIRQ_HXFRDN_IRQ ) {
|
if ( hirq & HIRQ_HXFRDN_IRQ ) {
|
||||||
reg_write(rhport, HIRQ_ADDR, HIRQ_HXFRDN_IRQ, true);
|
hirq_write(rhport, HIRQ_HXFRDN_IRQ, true);
|
||||||
handle_xfer_done(rhport);
|
handle_xfer_done(rhport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,7 +913,7 @@ void hcd_int_handler(uint8_t rhport) {
|
|||||||
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
|
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
|
||||||
hirq &= ~HIRQ_SNDBAV_IRQ;
|
hirq &= ~HIRQ_SNDBAV_IRQ;
|
||||||
if ( hirq ) {
|
if ( hirq ) {
|
||||||
reg_write(rhport, HIRQ_ADDR, hirq, true);
|
hirq_write(rhport, hirq, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user