I am porting ADB USB host project from Arduino UHS to FSL KL25Z. It is painful since the USB stacks have no common at all. Anyway I have almost finished my work until I tried to write low-level access functions like USB bulk read / bulk write.
In Arduino UHS ADB project, it is simple and forward, two functions are enough.
int USB::bulkWrite(usb_device * device, uint16_t length, uint8_t * data) // return int as USB status, 0x00 as successful
USB::write(device, &(device->bulk_out) , length, data);
max3421e_write(uint8_t reg, uint8_t value)
int USB::bulkRead(usb_device * device, uint16_t length, uint8_t * data, boolean poll) // return int as nr of bulk read successfully
USB::read(device, &(device->bulk_in), length, data, poll ? 1 : USB_NAK_LIMIT);
max3421e_write(uint8_t reg, uint8_t value)
max3421e_read(uint8_t reg)
The call is simple, application->class->USB->H/W.
Let us look into PHDC USB host project from FSL USB.
class\phdc\usb_host_phdc.c
USB_STATUS usb_class_phdc_recv_data( USB_PHDC_PARAM* call_param_ptr )
{
...usb_host_class_intf_validate(call_param_ptr ->ccs_ptr)...
usb_hostdev_tr_init (&tr, (tr_callback)usb_class_phdc_recv_data_callback, call_param_ptr);
tr.RX_BUFFER = call_param_ptr ->buff_ptr;
tr.RX_LENGTH = call_param_ptr ->buff_size;
call_param_ptr ->tr_index = tr.TR_INDEX;
call_param_ptr ->tr_pipe_handle = pipe;
usb_status = _usb_host_recv_data(phdc_cis_ptr ->generalClass.host_handle, pipe, &tr);
}
host_common\host_rcv.c
uint_32 _usb_host_recv_data( _usb_host_handle hci_handle, _usb_pipe_handle pipe_handle,TR_INIT_PARAM_STRUCT_PTR tr_params_ptr)
{
...status = _usb_host_recv_data_call_interface (hci_handle, pipe_descr_ptr, pipe_tr_ptr);
if (status == USB_OK)
return USB_STATUS_TRANSFER_QUEUED;
....
}
host_common\host_main.c
USB_STATUS _usb_host_recv_data_call_interface( _usb_host_handle handle, struct pipe_descriptor_struct _PTR_ pipe_descr_ptr, struct pipe_tr_struct _PTR_ pipe_tr_ptr)
{
...
temp_ptr = (USB_HOST_CALLBACK_FUNCTIONS_STRUCT_PTR)usb_host_ptr->CALLBACK_STRUCT_PTR;
if (temp_ptr->HOST_RECV != NULL){
error = temp_ptr->HOST_RECV (handle, pipe_descr_ptr, pipe_tr_ptr);
}
return error;
}
Here temp_ptr->HOST_RECV() is _usb_khci_recv() in khci_kinetis.c
khci_kinetis.c
USB_STATUS _usb_khci_recv(_usb_host_handle handle, PIPE_DESCRIPTOR_STRUCT_PTR pipe_desc_ptr, PIPE_TR_STRUCT_PTR pipe_tr_ptr)
{
msg.type = TR_MSG_RECV;
msg.pipe_desc = pipe_desc_ptr;
msg.pipe_tr = pipe_tr_ptr;
......
}
khci_kinetis.c
void _usb_khci_task(void)
{
case TR_MSG_RECV:
buf = msg.pipe_tr->RX_BUFFER;
remain = msg.pipe_tr->RX_LENGTH;
do{
res = _usb_khci_atom_tr(TR_IN, usb_host_state_struct_ptr->speed, msg.pipe_desc, buf, remain);
}while(1)
......
}
The whole process of USB bulkRead transfer implemented in FSL USB stack is:
- usb_class_phdc_recv_data() // application, class level call
- _usb_host_recv_data() // general purpose function for bulkIn
- _usb_host_recv_data_call_interface() // clue function to function map
- _usb_khci_recv() // push tr to message pool, and return from top of stack
- _usb_khci_task() // main loop
- _usb_khci_atom_tr() // real H/W API for register access
In current implementation, Application->Class->Clue->MessagePool, then return to main loop for H/W access. My question is:
How application knows how many bytes have been read? by _usb_khci_process_tr_complete() to notify application by callback functions like usb_class_phdc_recv_data_callback()?
FSL did offer many documentations for its USB stack. But we still need a design specification describing internal structure of USB stack, since it is much complex than other implementations.