make sure usb buffer occupies whole cache line when DCACHE is enabled for msc,cdc,hid

HIL enable device DMA for p4
This commit is contained in:
hathach 2024-11-21 10:15:30 +07:00
parent 2571889061
commit fa523a5682
No known key found for this signature in database
GPG Key ID: 26FAB84F615C3C52
10 changed files with 105 additions and 103 deletions

View File

@ -8,7 +8,7 @@
* in the Software without restriction, including without limitation the rights * in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is * copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * furnished to do so, subject to the following conditions:aaaaa
* *
* The above copyright notice and this permission notice shall be included in * The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software. * all copies or substantial portions of the Software.
@ -33,7 +33,7 @@
// #define NEOPIXEL_PIN 48 // #define NEOPIXEL_PIN 48
#define BUTTON_PIN 0 #define BUTTON_PIN 35
#define BUTTON_STATE_ACTIVE 0 #define BUTTON_STATE_ACTIVE 0
// For CI hardware test, to test both device and host on the same HS port with help of // For CI hardware test, to test both device and host on the same HS port with help of

View File

@ -69,8 +69,14 @@ typedef struct {
OSAL_MUTEX_DEF(tx_ff_mutex); OSAL_MUTEX_DEF(tx_ff_mutex);
// Endpoint Transfer buffer // Endpoint Transfer buffer
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; union {
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; CFG_TUD_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE];
TUD_DCACHE_PADDING;
};
union {
CFG_TUD_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE];
TUD_DCACHE_PADDING;
};
} cdcd_interface_t; } cdcd_interface_t;
#define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) #define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char)

View File

@ -53,9 +53,18 @@ typedef struct {
// Note: HID descriptor may be not available from application after enumeration // Note: HID descriptor may be not available from application after enumeration
tusb_hid_descriptor_hid_t const *hid_descriptor; tusb_hid_descriptor_hid_t const *hid_descriptor;
uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE]; union {
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE]; CFG_TUD_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE]; TUD_DCACHE_PADDING;
};
union {
CFG_TUD_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
TUD_DCACHE_PADDING;
};
union {
CFG_TUD_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
TUD_DCACHE_PADDING;
};
} hidd_interface_t; } hidd_interface_t;
CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID]; CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];

View File

@ -44,8 +44,7 @@
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF // MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
enum enum {
{
MSC_STAGE_CMD = 0, MSC_STAGE_CMD = 0,
MSC_STAGE_DATA, MSC_STAGE_DATA,
MSC_STAGE_STATUS, MSC_STAGE_STATUS,
@ -53,11 +52,19 @@ enum
MSC_STAGE_NEED_RESET, MSC_STAGE_NEED_RESET,
}; };
typedef struct typedef struct {
{ union {
// TODO optimize alignment CFG_TUD_MEM_ALIGN msc_cbw_t cbw;
CFG_TUSB_MEM_ALIGN msc_cbw_t cbw; TUD_DCACHE_PADDING;
CFG_TUSB_MEM_ALIGN msc_csw_t csw; };
union {
CFG_TUD_MEM_ALIGN msc_csw_t csw;
TUD_DCACHE_PADDING;
};
union {
CFG_TUD_MEM_ALIGN uint8_t ep_buf[CFG_TUD_MSC_EP_BUFSIZE];
TUD_DCACHE_PADDING;
};
uint8_t itf_num; uint8_t itf_num;
uint8_t ep_in; uint8_t ep_in;
@ -74,8 +81,7 @@ typedef struct
uint8_t add_sense_qualifier; uint8_t add_sense_qualifier;
}mscd_interface_t; }mscd_interface_t;
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static mscd_interface_t _mscd_itf; CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN static mscd_interface_t _mscd_itf;
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t _mscd_buf[CFG_TUD_MSC_EP_BUFSIZE];
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION // INTERNAL OBJECT & FUNCTION DECLARATION
@ -86,13 +92,11 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc); static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc);
static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes); static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint32_t xferred_bytes);
TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) TU_ATTR_ALWAYS_INLINE static inline bool is_data_in(uint8_t dir) {
{
return tu_bit_test(dir, 7); return tu_bit_test(dir, 7);
} }
static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc) {
{
// Data residue is always = host expect - actual transferred // Data residue is always = host expect - actual transferred
p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len; p_msc->csw.data_residue = p_msc->cbw.total_bytes - p_msc->xferred_len;
@ -100,14 +104,12 @@ static inline bool send_csw(uint8_t rhport, mscd_interface_t* p_msc)
return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)); return usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t));
} }
static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) static inline bool prepare_cbw(uint8_t rhport, mscd_interface_t* p_msc) {
{
p_msc->stage = MSC_STAGE_CMD; p_msc->stage = MSC_STAGE_CMD;
return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)); return usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t));
} }
static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status) {
{
msc_cbw_t const * p_cbw = &p_msc->cbw; msc_cbw_t const * p_cbw = &p_msc->cbw;
msc_csw_t * p_csw = &p_msc->csw; msc_csw_t * p_csw = &p_msc->csw;
@ -116,24 +118,21 @@ static void fail_scsi_op(uint8_t rhport, mscd_interface_t* p_msc, uint8_t status
p_msc->stage = MSC_STAGE_STATUS; p_msc->stage = MSC_STAGE_STATUS;
// failed but sense key is not set: default to Illegal Request // failed but sense key is not set: default to Illegal Request
if ( p_msc->sense_key == 0 ) tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); if (p_msc->sense_key == 0) {
tud_msc_set_sense(p_cbw->lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
}
// If there is data stage and not yet complete, stall it // If there is data stage and not yet complete, stall it
if ( p_cbw->total_bytes && p_csw->data_residue ) if (p_cbw->total_bytes && p_csw->data_residue) {
{ if (is_data_in(p_cbw->dir)) {
if ( is_data_in(p_cbw->dir) )
{
usbd_edpt_stall(rhport, p_msc->ep_in); usbd_edpt_stall(rhport, p_msc->ep_in);
} } else {
else
{
usbd_edpt_stall(rhport, p_msc->ep_out); usbd_edpt_stall(rhport, p_msc->ep_out);
} }
} }
} }
static inline uint32_t rdwr10_get_lba(uint8_t const command[]) static inline uint32_t rdwr10_get_lba(uint8_t const command[]) {
{
// use offsetof to avoid pointer to the odd/unaligned address // use offsetof to avoid pointer to the odd/unaligned address
uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba)); uint32_t const lba = tu_unaligned_read32(command + offsetof(scsi_write10_t, lba));
@ -141,14 +140,12 @@ static inline uint32_t rdwr10_get_lba(uint8_t const command[])
return tu_ntohl(lba); return tu_ntohl(lba);
} }
static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) static inline uint16_t rdwr10_get_blockcount(msc_cbw_t const* cbw) {
{
uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count)); uint16_t const block_count = tu_unaligned_read16(cbw->command + offsetof(scsi_write10_t, block_count));
return tu_ntohs(block_count); return tu_ntohs(block_count);
} }
static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw) {
{
// first extract block count in the command // first extract block count in the command
uint16_t const block_count = rdwr10_get_blockcount(cbw); uint16_t const block_count = rdwr10_get_blockcount(cbw);
@ -158,40 +155,28 @@ static inline uint16_t rdwr10_get_blocksize(msc_cbw_t const* cbw)
return (uint16_t) (cbw->total_bytes / block_count); return (uint16_t) (cbw->total_bytes / block_count);
} }
uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw) {
{
uint8_t status = MSC_CSW_STATUS_PASSED; uint8_t status = MSC_CSW_STATUS_PASSED;
uint16_t const block_count = rdwr10_get_blockcount(cbw); uint16_t const block_count = rdwr10_get_blockcount(cbw);
if ( cbw->total_bytes == 0 ) if (cbw->total_bytes == 0) {
{ if (block_count) {
if ( block_count )
{
TU_LOG_DRV(" SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n"); TU_LOG_DRV(" SCSI case 2 (Hn < Di) or case 3 (Hn < Do) \r\n");
status = MSC_CSW_STATUS_PHASE_ERROR; status = MSC_CSW_STATUS_PHASE_ERROR;
}else } else {
{
// no data transfer, only exist in complaint test suite // no data transfer, only exist in complaint test suite
} }
}else } else {
{ if (SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir)) {
if ( SCSI_CMD_READ_10 == cbw->command[0] && !is_data_in(cbw->dir) )
{
TU_LOG_DRV(" SCSI case 10 (Ho <> Di)\r\n"); TU_LOG_DRV(" SCSI case 10 (Ho <> Di)\r\n");
status = MSC_CSW_STATUS_PHASE_ERROR; status = MSC_CSW_STATUS_PHASE_ERROR;
} } else if (SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir)) {
else if ( SCSI_CMD_WRITE_10 == cbw->command[0] && is_data_in(cbw->dir) )
{
TU_LOG_DRV(" SCSI case 8 (Hi <> Do)\r\n"); TU_LOG_DRV(" SCSI case 8 (Hi <> Do)\r\n");
status = MSC_CSW_STATUS_PHASE_ERROR; status = MSC_CSW_STATUS_PHASE_ERROR;
} } else if (0 == block_count) {
else if ( 0 == block_count )
{
TU_LOG_DRV(" SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n"); TU_LOG_DRV(" SCSI case 4 Hi > Dn (READ10) or case 9 Ho > Dn (WRITE10) \r\n");
status = MSC_CSW_STATUS_FAILED; status = MSC_CSW_STATUS_FAILED;
} } else if (cbw->total_bytes / block_count == 0) {
else if ( cbw->total_bytes / block_count == 0 )
{
TU_LOG_DRV(" Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n"); TU_LOG_DRV(" Computed block size = 0. SCSI case 7 Hi < Di (READ10) or case 13 Ho < Do (WRIT10)\r\n");
status = MSC_CSW_STATUS_PHASE_ERROR; status = MSC_CSW_STATUS_PHASE_ERROR;
} }
@ -205,8 +190,7 @@ uint8_t rdwr10_validate_cmd(msc_cbw_t const* cbw)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= CFG_TUD_MSC_LOG_LEVEL #if CFG_TUSB_DEBUG >= CFG_TUD_MSC_LOG_LEVEL
TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] = {
{
{ .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" }, { .key = SCSI_CMD_TEST_UNIT_READY , .data = "Test Unit Ready" },
{ .key = SCSI_CMD_INQUIRY , .data = "Inquiry" }, { .key = SCSI_CMD_INQUIRY , .data = "Inquiry" },
{ .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" }, { .key = SCSI_CMD_MODE_SELECT_6 , .data = "Mode_Select 6" },
@ -220,8 +204,7 @@ TU_ATTR_UNUSED tu_static tu_lookup_entry_t const _msc_scsi_cmd_lookup[] =
{ .key = SCSI_CMD_WRITE_10 , .data = "Write10" } { .key = SCSI_CMD_WRITE_10 , .data = "Write10" }
}; };
TU_ATTR_UNUSED tu_static tu_lookup_table_t const _msc_scsi_cmd_table = TU_ATTR_UNUSED tu_static tu_lookup_table_t const _msc_scsi_cmd_table = {
{
.count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup), .count = TU_ARRAY_SIZE(_msc_scsi_cmd_lookup),
.items = _msc_scsi_cmd_lookup .items = _msc_scsi_cmd_lookup
}; };
@ -462,7 +445,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length // 2. IN & Zero: Process if is built-in, else Invoke app callback. Skip DATA if zero length
if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) ) if ( (p_cbw->total_bytes > 0 ) && !is_data_in(p_cbw->dir) )
{ {
if (p_cbw->total_bytes > sizeof(_mscd_buf)) if (p_cbw->total_bytes > CFG_TUD_MSC_EP_BUFSIZE)
{ {
TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n"); TU_LOG_DRV(" SCSI reject non READ10/WRITE10 with large data\r\n");
fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED); fail_scsi_op(rhport, p_msc, MSC_CSW_STATUS_FAILED);
@ -470,17 +453,17 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
{ {
// Didn't check for case 9 (Ho > Dn), which requires examining scsi command first // Didn't check for case 9 (Ho > Dn), which requires examining scsi command first
// but it is OK to just receive data then responded with failed status // but it is OK to just receive data then responded with failed status
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, (uint16_t) p_msc->total_len) ); TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, p_msc->ep_buf, (uint16_t) p_msc->total_len) );
} }
}else }else
{ {
// First process if it is a built-in commands // First process if it is a built-in commands
int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, _mscd_buf, sizeof(_mscd_buf)); int32_t resplen = proc_builtin_scsi(p_cbw->lun, p_cbw->command, p_msc->ep_buf, CFG_TUD_MSC_EP_BUFSIZE);
// Invoke user callback if not built-in // Invoke user callback if not built-in
if ( (resplen < 0) && (p_msc->sense_key == 0) ) if ( (resplen < 0) && (p_msc->sense_key == 0) )
{ {
resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); resplen = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, p_msc->ep_buf, (uint16_t) p_msc->total_len);
} }
if ( resplen < 0 ) if ( resplen < 0 )
@ -513,7 +496,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
{ {
// cannot return more than host expect // cannot return more than host expect
p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes); p_msc->total_len = tu_min32((uint32_t) resplen, p_cbw->total_bytes);
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) p_msc->total_len) ); TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, p_msc->ep_buf, (uint16_t) p_msc->total_len) );
} }
} }
} }
@ -522,7 +505,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
case MSC_STAGE_DATA: case MSC_STAGE_DATA:
TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun); TU_LOG_DRV(" SCSI Data [Lun%u]\r\n", p_cbw->lun);
//TU_LOG_MEM(MSC_DEBUG, _mscd_buf, xferred_bytes, 2); //TU_LOG_MEM(MSC_DEBUG, p_msc->ep_buf, xferred_bytes, 2);
if (SCSI_CMD_READ_10 == p_cbw->command[0]) if (SCSI_CMD_READ_10 == p_cbw->command[0])
{ {
@ -548,7 +531,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
// OUT transfer, invoke callback if needed // OUT transfer, invoke callback if needed
if ( !is_data_in(p_cbw->dir) ) if ( !is_data_in(p_cbw->dir) )
{ {
int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, _mscd_buf, (uint16_t) p_msc->total_len); int32_t cb_result = tud_msc_scsi_cb(p_cbw->lun, p_cbw->command, p_msc->ep_buf, (uint16_t) p_msc->total_len);
if ( cb_result < 0 ) if ( cb_result < 0 )
{ {
@ -861,11 +844,11 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz); uint32_t const lba = rdwr10_get_lba(p_cbw->command) + (p_msc->xferred_len / block_sz);
// remaining bytes capped at class buffer // remaining bytes capped at class buffer
int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); int32_t nbytes = (int32_t) tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes-p_msc->xferred_len);
// Application can consume smaller bytes // Application can consume smaller bytes
uint32_t const offset = p_msc->xferred_len % block_sz; uint32_t const offset = p_msc->xferred_len % block_sz;
nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, _mscd_buf, (uint32_t) nbytes); nbytes = tud_msc_read10_cb(p_cbw->lun, lba, offset, p_msc->ep_buf, (uint32_t) nbytes);
if ( nbytes < 0 ) if ( nbytes < 0 )
{ {
@ -884,7 +867,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
} }
else else
{ {
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, (uint16_t) nbytes), ); TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, p_msc->ep_buf, (uint16_t) nbytes), );
} }
} }
@ -908,10 +891,10 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
} }
// remaining bytes capped at class buffer // remaining bytes capped at class buffer
uint16_t nbytes = (uint16_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len); uint16_t nbytes = (uint16_t) tu_min32(CFG_TUD_MSC_EP_BUFSIZE, p_cbw->total_bytes-p_msc->xferred_len);
// Write10 callback will be called later when usb transfer complete // Write10 callback will be called later when usb transfer complete
TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), ); TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, p_msc->ep_buf, nbytes), );
} }
// process new data arrived from WRITE10 // process new data arrived from WRITE10
@ -927,7 +910,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
// Invoke callback to consume new data // Invoke callback to consume new data
uint32_t const offset = p_msc->xferred_len % block_sz; uint32_t const offset = p_msc->xferred_len % block_sz;
int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, _mscd_buf, xferred_bytes); int32_t nbytes = tud_msc_write10_cb(p_cbw->lun, lba, offset, p_msc->ep_buf, xferred_bytes);
if ( nbytes < 0 ) if ( nbytes < 0 )
{ {
@ -950,7 +933,7 @@ static void proc_write10_new_data(uint8_t rhport, mscd_interface_t* p_msc, uint3
if ( nbytes > 0 ) if ( nbytes > 0 )
{ {
p_msc->xferred_len += (uint16_t) nbytes; p_msc->xferred_len += (uint16_t) nbytes;
memmove(_mscd_buf, _mscd_buf+nbytes, left_over); memmove(p_msc->ep_buf, p_msc->ep_buf+nbytes, left_over);
} }
// simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter // simulate an transfer complete with adjusted parameters --> callback will be invoked with adjusted parameter

View File

@ -58,6 +58,9 @@
// Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111 // Generate a mask with bit from high (31) to low (0) set, e.g TU_GENMASK(3, 0) = 0b1111
#define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) ) #define TU_GENMASK(h, l) ( (UINT32_MAX << (l)) & (UINT32_MAX >> (31 - (h))) )
// DCache padding for variable to occupy full cache line
#define TUD_DCACHE_PADDING uint8_t TU_XSTRCAT(dcache_padding_, _TU_COUNTER_)[CFG_TUD_MEM_DCACHE_ENABLE ? CFG_TUD_MEM_DCACHE_LINE_SIZE : 1]
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Includes // Includes
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+

View File

@ -136,7 +136,7 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak)) #define TU_ATTR_WEAK __attribute__ ((weak))
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)) // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
#ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
#endif #endif
@ -189,6 +189,7 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak)) #define TU_ATTR_WEAK __attribute__ ((weak))
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
#define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used #define TU_ATTR_DEPRECATED(mess) __attribute__ ((deprecated(mess))) // warn if function with this attribute is used
#define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused #define TU_ATTR_UNUSED __attribute__ ((unused)) // Function/Variable is meant to be possibly unused
@ -216,6 +217,7 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name))) #define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed)) #define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak)) #define TU_ATTR_WEAK __attribute__ ((weak))
// #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f)))
#ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug #ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline)) #define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
#endif #endif
@ -244,6 +246,7 @@
#define TU_ATTR_SECTION(sec_name) #define TU_ATTR_SECTION(sec_name)
#define TU_ATTR_PACKED #define TU_ATTR_PACKED
#define TU_ATTR_WEAK #define TU_ATTR_WEAK
// #define TU_ATTR_WEAK_ALIAS(f)
#define TU_ATTR_ALWAYS_INLINE #define TU_ATTR_ALWAYS_INLINE
#define TU_ATTR_DEPRECATED(mess) #define TU_ATTR_DEPRECATED(mess)
#define TU_ATTR_UNUSED #define TU_ATTR_UNUSED

View File

@ -54,6 +54,10 @@ enum {
}; };
typedef struct { typedef struct {
union {
CFG_TUD_MEM_ALIGN uint8_t ep_buf[CFG_TUD_ENDPOINT0_SIZE];
TUD_DCACHE_PADDING;
};
tusb_control_request_t request; tusb_control_request_t request;
uint8_t* buffer; uint8_t* buffer;
uint16_t data_len; uint16_t data_len;
@ -61,17 +65,14 @@ typedef struct {
usbd_control_xfer_cb_t complete_cb; usbd_control_xfer_cb_t complete_cb;
} usbd_control_xfer_t; } usbd_control_xfer_t;
tu_static usbd_control_xfer_t _ctrl_xfer; CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN static usbd_control_xfer_t _ctrl_xfer;
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN
tu_static uint8_t _usbd_ctrl_buf[CFG_TUD_ENDPOINT0_SIZE];
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Application API // Application API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Queue ZLP status transaction // Queue ZLP status transaction
static inline bool _status_stage_xact(uint8_t rhport, tusb_control_request_t const* request) { static inline bool status_stage_xact(uint8_t rhport, tusb_control_request_t const* request) {
// Opposite to endpoint in Data Phase // Opposite to endpoint in Data Phase
uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN; uint8_t const ep_addr = request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN;
return usbd_edpt_xfer(rhport, ep_addr, NULL, 0); return usbd_edpt_xfer(rhport, ep_addr, NULL, 0);
@ -84,13 +85,13 @@ bool tud_control_status(uint8_t rhport, tusb_control_request_t const* request) {
_ctrl_xfer.total_xferred = 0; _ctrl_xfer.total_xferred = 0;
_ctrl_xfer.data_len = 0; _ctrl_xfer.data_len = 0;
return _status_stage_xact(rhport, request); return status_stage_xact(rhport, request);
} }
// Queue a transaction in Data Stage // Queue a transaction in Data Stage
// Each transaction has up to Endpoint0's max packet size. // Each transaction has up to Endpoint0's max packet size.
// This function can also transfer an zero-length packet // This function can also transfer an zero-length packet
static bool _data_stage_xact(uint8_t rhport) { static bool data_stage_xact(uint8_t rhport) {
uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred, uint16_t const xact_len = tu_min16(_ctrl_xfer.data_len - _ctrl_xfer.total_xferred,
CFG_TUD_ENDPOINT0_SIZE); CFG_TUD_ENDPOINT0_SIZE);
@ -99,11 +100,11 @@ static bool _data_stage_xact(uint8_t rhport) {
if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) { if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_IN) {
ep_addr = EDPT_CTRL_IN; ep_addr = EDPT_CTRL_IN;
if (xact_len) { if (xact_len) {
TU_VERIFY(0 == tu_memcpy_s(_usbd_ctrl_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len)); TU_VERIFY(0 == tu_memcpy_s(_ctrl_xfer.ep_buf, CFG_TUD_ENDPOINT0_SIZE, _ctrl_xfer.buffer, xact_len));
} }
} }
return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _usbd_ctrl_buf : NULL, xact_len); return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _ctrl_xfer.ep_buf : NULL, xact_len);
} }
// Transmit data to/from the control endpoint. // Transmit data to/from the control endpoint.
@ -122,10 +123,10 @@ bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const* request, voi
// TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len); // TU_LOG2(" Control total data length is %u bytes\r\n", _ctrl_xfer.data_len);
// Data stage // Data stage
TU_ASSERT(_data_stage_xact(rhport)); TU_ASSERT(data_stage_xact(rhport));
} else { } else {
// Status stage // Status stage
TU_ASSERT(_status_stage_xact(rhport, request)); TU_ASSERT(status_stage_xact(rhport, request));
} }
return true; return true;
@ -179,7 +180,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) { if (_ctrl_xfer.request.bmRequestType_bit.direction == TUSB_DIR_OUT) {
TU_VERIFY(_ctrl_xfer.buffer); TU_VERIFY(_ctrl_xfer.buffer);
memcpy(_ctrl_xfer.buffer, _usbd_ctrl_buf, xferred_bytes); memcpy(_ctrl_xfer.buffer, _ctrl_xfer.ep_buf, xferred_bytes);
TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2); TU_LOG_MEM(CFG_TUD_LOG_LEVEL, _usbd_ctrl_buf, xferred_bytes, 2);
} }
@ -205,7 +206,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
if (is_ok) { if (is_ok) {
// Send status // Send status
TU_ASSERT(_status_stage_xact(rhport, &_ctrl_xfer.request)); TU_ASSERT(status_stage_xact(rhport, &_ctrl_xfer.request));
} else { } else {
// Stall both IN and OUT control endpoint // Stall both IN and OUT control endpoint
dcd_edpt_stall(rhport, EDPT_CTRL_OUT); dcd_edpt_stall(rhport, EDPT_CTRL_OUT);
@ -213,7 +214,7 @@ bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result,
} }
} else { } else {
// More data to transfer // More data to transfer
TU_ASSERT(_data_stage_xact(rhport)); TU_ASSERT(data_stage_xact(rhport));
} }
return true; return true;

View File

@ -58,11 +58,9 @@ static xfer_ctl_t xfer_status[DWC2_EP_MAX][2];
#define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir]) #define XFER_CTL_BASE(_ep, _dir) (&xfer_status[_ep][_dir])
typedef struct { typedef struct {
CFG_TUD_MEM_ALIGN union { union {
uint32_t setup_packet[2]; CFG_TUD_MEM_ALIGN uint32_t setup_packet[2];
#if CFG_TUD_MEM_DCACHE_ENABLE TUD_DCACHE_PADDING;
uint8_t setup_packet_cache_padding[CFG_TUD_MEM_DCACHE_LINE_SIZE];
#endif
}; };
// EP0 transfers are limited to 1 packet - larger sizes has to be split // EP0 transfers are limited to 1 packet - larger sizes has to be split

View File

@ -252,11 +252,7 @@
#define CFG_TUD_DWC2_SLAVE_ENABLE 1 #define CFG_TUD_DWC2_SLAVE_ENABLE 1
#endif #endif
// DWC2 controller: use DMA for data transfer // Enable DWC2 DMA for device
// For processors with data cache enabled, USB endpoint buffer region
// (defined by CFG_TUSB_MEM_SECTION) must be declared as non-cacheable.
// For example, on Cortex-M7 the MPU region can be configured as normal
// non-cacheable, with RASR register value: TEX=1 C=0 B=0 S=0.
#ifndef CFG_TUD_DWC2_DMA_ENABLE #ifndef CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUD_DWC2_DMA_ENABLE 0 #define CFG_TUD_DWC2_DMA_ENABLE 0
#endif #endif

View File

@ -3,6 +3,9 @@
{ {
"name": "espressif_p4_function_ev", "name": "espressif_p4_function_ev",
"uid": "6055F9F98715", "uid": "6055F9F98715",
"build" : {
"flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"]
},
"tests": { "tests": {
"only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"],
"dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427"}] "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427"}]