Simple USBHost library for Nucleo F446RE/F411RE/F401RE FRDM-KL46Z/KL25Z/F64F LPC4088/LPC1768

Dependencies:   FATFileSystem

Dependents:   F401RE-BTstack_example F401RE-USBHostMSD_HelloWorld

Fork of KL46Z-USBHost by Norimasa Okamoto

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers USBHALHost_F401RE.cpp Source File

USBHALHost_F401RE.cpp

00001 #if defined(TARGET_NUCLEO_F401RE)||defined(TARGET_NUCLEO_F411RE)||defined(TARGET_NUCLEO_F446RE)
00002 #include "USBHALHost.h"
00003 #include <algorithm>
00004 
00005 #ifdef _USB_DBG
00006 extern RawSerial pc;
00007 //RawSerial pc(USBTX,USBRX);
00008 #include "mydebug.h"
00009 #define USB_DBG(...) do{pc.printf("[%s@%d] ",__PRETTY_FUNCTION__,__LINE__);pc.printf(__VA_ARGS__);pc.puts("\n");} while(0);
00010 #define USB_DBG_HEX(A,B) debug_hex<RawSerial>(pc,A,B)
00011 
00012 #else
00013 #define USB_DBG(...) while(0)
00014 #define USB_DBG_HEX(A,B) while(0)
00015 #endif
00016 
00017 #undef USB_TEST_ASSERT
00018 void usb_test_assert_internal(const char *expr, const char *file, int line);
00019 #define USB_TEST_ASSERT(EXPR) while(!(EXPR)){usb_test_assert_internal(#EXPR,__FILE__,__LINE__);}
00020 
00021 #define USB_TRACE1(A) while(0)
00022 
00023 #define USB_INFO(...) do{fprintf(stderr,__VA_ARGS__);fprintf(stderr,"\n");}while(0);
00024 
00025 __IO bool attach_done = false;
00026 
00027 void delay_ms(uint32_t t)
00028 {
00029     HAL_Delay(t);
00030 }
00031 
00032 // usbh_conf.c
00033 extern HCD_HandleTypeDef hhcd_USB_OTG_FS;
00034 
00035 void HAL_HCD_MspInit(HCD_HandleTypeDef* hhcd)
00036 {
00037   GPIO_InitTypeDef GPIO_InitStruct;
00038   if(hhcd->Instance==USB_OTG_FS)
00039   {
00040     /* Peripheral clock enable */
00041     __USB_OTG_FS_CLK_ENABLE();
00042   
00043     /**USB_OTG_FS GPIO Configuration    
00044     PA11     ------> USB_OTG_FS_DM
00045     PA12     ------> USB_OTG_FS_DP 
00046     */
00047     GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12;
00048     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
00049     GPIO_InitStruct.Pull = GPIO_NOPULL;
00050     GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
00051     GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
00052     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
00053 
00054     /* Peripheral interrupt init*/
00055     /* Sets the priority grouping field */
00056     HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
00057     HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0);
00058     HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
00059   }
00060 }
00061 
00062 // stm32f4xx_it.c
00063 extern "C" {
00064 void HAL_HCD_Connect_Callback(HCD_HandleTypeDef *hhcd)
00065 {
00066     USB_TRACE1(hhcd);
00067     attach_done = true;
00068 }
00069 
00070 } // extern "C"
00071 
00072 USBHALHost* USBHALHost::instHost;
00073 
00074 USBHALHost::USBHALHost() {
00075     instHost = this;
00076 }
00077 
00078 void USBHALHost::init() {
00079     hhcd_USB_OTG_FS.Instance = USB_OTG_FS;
00080     hhcd_USB_OTG_FS.Init.Host_channels = 8;
00081     hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL;
00082     hhcd_USB_OTG_FS.Init.dma_enable = DISABLE;
00083     hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED;
00084     hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
00085     hhcd_USB_OTG_FS.Init.low_power_enable = ENABLE;
00086     hhcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
00087     hhcd_USB_OTG_FS.Init.use_external_vbus = DISABLE;
00088 
00089     HAL_HCD_Init(&hhcd_USB_OTG_FS);
00090     HAL_HCD_Start(&hhcd_USB_OTG_FS);
00091 
00092     bool lowSpeed = wait_attach();
00093     delay_ms(200);
00094     HAL_HCD_ResetPort(&hhcd_USB_OTG_FS);
00095     delay_ms(100); // Wait for 100 ms after Reset
00096     addDevice(NULL, 0, lowSpeed);
00097 }
00098 
00099 bool USBHALHost::wait_attach() {
00100     Timer t;
00101     t.reset();
00102     t.start();
00103     while(!attach_done) {
00104         if (t.read_ms() > 5*1000) {
00105             t.reset();
00106             USB_INFO("Please attach USB device.");
00107         }
00108     }
00109     wait_ms(100);
00110     return HAL_HCD_GetCurrentSpeed(&hhcd_USB_OTG_FS) == USB_OTG_SPEED_LOW;
00111 }
00112 
00113 int USBHALHost::token_setup(USBEndpoint* ep, SETUP_PACKET* setup, uint16_t wLength) {
00114     const uint8_t ep_addr = 0x00;
00115     HC hc;
00116     USBDeviceConnected* dev = ep->getDevice();
00117     hc.Init(ep_addr, 
00118         dev->getAddress(),
00119         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
00120         EP_TYPE_CTRL, ep->getSize());
00121 
00122     setup->wLength = wLength;
00123     hc.SubmitRequest((uint8_t*)setup, 8, true); // PID_SETUP
00124     while(hc.GetURBState() == URB_IDLE);
00125 
00126     switch(hc.GetURBState()) {
00127         case URB_DONE:
00128             LastStatus = ACK;
00129             break;
00130         default:
00131             LastStatus = 0xff;
00132             break;
00133     }
00134     ep->setData01(DATA1);
00135     return 8;
00136 }
00137 
00138 int USBHALHost::token_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
00139     switch(ep->getType()) {
00140         case CONTROL_ENDPOINT:
00141             return token_ctl_in(ep, data, size, retryLimit);
00142         case INTERRUPT_ENDPOINT:
00143             return token_int_in(ep, data, size);
00144         case BULK_ENDPOINT:
00145             return token_blk_in(ep, data, size, retryLimit);
00146     }
00147     return -1;
00148 }
00149 
00150 int USBHALHost::token_ctl_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
00151     const uint8_t ep_addr = 0x80;
00152     HC hc;
00153     USBDeviceConnected* dev = ep->getDevice();
00154     hc.Init(ep_addr, 
00155         dev->getAddress(),
00156         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
00157         EP_TYPE_CTRL, ep->getSize());
00158 
00159     hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
00160 
00161     hc.SubmitRequest(data, size);
00162     while(hc.GetURBState() == URB_IDLE);
00163 
00164     switch(hc.GetURBState()) {
00165         case URB_DONE:
00166             LastStatus = ACK;
00167             break;
00168         default:
00169             LastStatus = 0xff;
00170             return -1;
00171     }
00172     ep->toggleData01();
00173     return hc.GetXferCount();
00174 }
00175 
00176 int USBHALHost::token_int_in(USBEndpoint* ep, uint8_t* data, int size) {
00177     HC hc;
00178     USBDeviceConnected* dev = ep->getDevice();
00179     hc.Init(
00180         ep->getAddress(),
00181         dev->getAddress(),
00182         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
00183         EP_TYPE_INTR, ep->getSize());
00184 
00185     hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
00186 
00187     hc.SubmitRequest(data, size);
00188     while(hc.GetURBState() == URB_IDLE);
00189     switch(hc.GetURBState()) {
00190         case URB_DONE:
00191             switch(hc.GetState()) {
00192                 case HC_XFRC:
00193                     LastStatus = ep->getData01();
00194                     ep->toggleData01();
00195                     return hc.GetXferCount();
00196                 case HC_NAK:
00197                     LastStatus = NAK;
00198                     return -1;
00199             }
00200             break;
00201     }
00202     LastStatus = STALL;
00203     return -1;
00204 }
00205 
00206 int USBHALHost::token_blk_in(USBEndpoint* ep, uint8_t* data, int size, int retryLimit) {
00207     HC hc;
00208     USBDeviceConnected* dev = ep->getDevice();
00209     hc.Init(
00210         ep->getAddress(),
00211         dev->getAddress(),
00212         HCD_SPEED_FULL,
00213         EP_TYPE_BULK, ep->getSize());
00214 
00215     hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
00216 
00217     int retry = 0;
00218     do {
00219         hc.SubmitRequest(data, size);
00220         while(hc.GetURBState() == URB_IDLE);
00221 
00222         switch(hc.GetURBState()) {
00223             case URB_DONE:
00224                 switch(hc.GetState()) {
00225                     case HC_XFRC:
00226                         LastStatus = ep->getData01();
00227                         ep->toggleData01();
00228                         return hc.GetXferCount();
00229                     case HC_NAK:
00230                         LastStatus = NAK;
00231                         if (retryLimit > 0) {
00232                             delay_ms(1 + 10 * retry);
00233                         }
00234                         break;
00235                     default:
00236                         break;
00237                 }
00238                 break;
00239             case URB_STALL:
00240                 LastStatus = STALL;
00241                 return -1;
00242             default:
00243                 LastStatus = STALL;
00244                 delay_ms(500 + 100 * retry);
00245                 break;
00246         }
00247     }while(retry++ < retryLimit);
00248     return -1;
00249 }
00250 
00251 int USBHALHost::token_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
00252     switch(ep->getType()) {
00253         case CONTROL_ENDPOINT:
00254             return token_ctl_out(ep, data, size, retryLimit);
00255         case INTERRUPT_ENDPOINT:
00256             return token_int_out(ep, data, size);
00257         case BULK_ENDPOINT:
00258             return token_blk_out(ep, data, size, retryLimit);
00259     }
00260     return -1;
00261 }
00262 
00263 int USBHALHost::token_ctl_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
00264     const uint8_t ep_addr = 0x00;
00265     HC hc;
00266     USBDeviceConnected* dev = ep->getDevice();
00267     hc.Init(ep_addr, 
00268         dev->getAddress(),
00269         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
00270         EP_TYPE_CTRL, ep->getSize());
00271 
00272     hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
00273 
00274     do {
00275         hc.SubmitRequest((uint8_t*)data, size);
00276         while(hc.GetURBState() == URB_IDLE);
00277 
00278         switch(hc.GetURBState()) {
00279             case URB_DONE:
00280                 LastStatus = ACK;
00281                 ep->toggleData01();
00282                 return size;
00283 
00284             default:
00285                 break;
00286         }
00287         delay_ms(1);
00288     }while(retryLimit-- > 0); 
00289     return -1;
00290 }
00291 
00292 int USBHALHost::token_int_out(USBEndpoint* ep, const uint8_t* data, int size) {
00293     HC hc;
00294     USBDeviceConnected* dev = ep->getDevice();
00295     hc.Init(
00296         ep->getAddress(),
00297         dev->getAddress(),
00298         dev->getSpeed() ? HCD_SPEED_LOW : HCD_SPEED_FULL,
00299         EP_TYPE_INTR, ep->getSize());
00300 
00301     hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
00302 
00303     hc.SubmitRequest((uint8_t*)data, size);
00304     while(hc.GetURBState() == URB_IDLE);
00305     if (hc.GetURBState() != URB_DONE) {
00306         return -1;
00307     }
00308     ep->toggleData01();
00309     return size;
00310 }
00311 
00312 int USBHALHost::token_blk_out(USBEndpoint* ep, const uint8_t* data, int size, int retryLimit) {
00313     HC hc;
00314     USBDeviceConnected* dev = ep->getDevice();
00315     hc.Init(
00316         ep->getAddress(), dev->getAddress(),
00317         HCD_SPEED_FULL, EP_TYPE_BULK, ep->getSize());
00318 
00319     hc.SetToggle((ep->getData01() == DATA0) ? 0 : 1);
00320 
00321     int retry = 0;
00322     do {
00323         hc.SubmitRequest((uint8_t*)data, size);
00324         while(hc.GetURBState() == URB_IDLE);
00325 
00326         switch(hc.GetURBState()) {
00327             case URB_DONE:
00328                 switch(hc.GetState()) {
00329                     case HC_XFRC: // ACK
00330                         LastStatus = ep->getData01();
00331                         ep->toggleData01();
00332                         return size;
00333                     default:
00334                         break;
00335                 }
00336                 break;
00337             case URB_NOTREADY: // HC_NAK
00338                 LastStatus = NAK;
00339                 delay_ms(100 * retry);
00340                 break;
00341             default:
00342                 LastStatus = STALL;
00343                 return -1;
00344         }
00345     } while(retry++ < retryLimit);
00346     return -1;
00347 }
00348 
00349 int USBHALHost::token_iso_in(USBEndpoint* ep, uint8_t* data, int size) {
00350     HC* hc = ep->getHALData<HC*>();
00351     if (hc == NULL) {
00352         hc = new HC;
00353         ep->setHALData<HC*>(hc);
00354         USBDeviceConnected* dev = ep->getDevice();
00355         hc->Init(
00356             ep->getAddress(), dev->getAddress(),
00357             HCD_SPEED_FULL, EP_TYPE_ISOC, ep->getSize());
00358     }
00359     hc->SubmitRequest(data, size);
00360     while(hc->GetURBState() == URB_IDLE);
00361     return hc->GetXferCount();
00362 }
00363 
00364 int USBHALHost::multi_token_in(USBEndpoint* ep, uint8_t* data, size_t total, bool block) {
00365     if (total == 0) {
00366         return token_in(ep);
00367     }
00368     int retryLimit = block ? 10 : 0;
00369     int read_len = 0;
00370     for(int n = 0; read_len < total; n++) {
00371         int size = std::min((int)total-read_len, ep->getSize());
00372         int result = token_in(ep, data+read_len, size, retryLimit);
00373         if (result < 0) {
00374             if (block) {
00375                 return -1;
00376             }
00377             if (LastStatus == NAK) {
00378                 if (n == 0) {
00379                     return -1;
00380                 }
00381                 break;
00382             }
00383             return result;
00384         }
00385         read_len += result;
00386         if (result < ep->getSize()) {
00387             break;
00388         }
00389     }
00390     return read_len;
00391 }
00392 
00393 int USBHALHost::multi_token_out(USBEndpoint* ep, const uint8_t* data, size_t total) {
00394     if (total == 0) {
00395         return token_out(ep);
00396     }
00397     int write_len = 0;
00398     for(int n = 0; write_len < total; n++) {
00399         int size = std::min((int)total-write_len, ep->getSize());
00400         int result = token_out(ep, data+write_len, size);
00401         if (result < 0) {
00402             if (LastStatus == NAK) {
00403                 if (n == 0) {
00404                     return -1;
00405                 }
00406                 break;
00407             }
00408             USB_DBG("token_out result=%d %02x", result, LastStatus);
00409             return result;
00410         }
00411         write_len += result;
00412         if (result < ep->getSize()) {
00413             break;
00414         }
00415     }
00416     return write_len;
00417 }
00418 void USBHALHost::multi_token_inNB(USBEndpoint* ep, uint8_t* data, int size) {
00419     USB_TRACE1(size);
00420     USB_TEST_ASSERT(ep->getState() != USB_TYPE_PROCESSING);
00421     ep->setBuffer(data, size);
00422     ep->setState(USB_TYPE_PROCESSING);
00423 }
00424 
00425 USB_TYPE USBHALHost::multi_token_inNB_result(USBEndpoint* ep) {
00426     USB_TEST_ASSERT(ep->getState() == USB_TYPE_PROCESSING);
00427     uint8_t* buf = ep->getBufStart();
00428     int size = ep->getBufSize();
00429     int result = multi_token_in(ep, buf, size, false);
00430     USB_TRACE1(result);
00431     if (result < 0) {
00432         return USB_TYPE_PROCESSING;
00433     }
00434     ep->setLengthTransferred(result);
00435     ep->setState(USB_TYPE_IDLE);
00436     return USB_TYPE_OK;
00437 
00438 }
00439 
00440 void USBHALHost::setToggle(USBEndpoint* ep, uint8_t toggle) {
00441     USB_TEST_ASSERT(toggle == 1);
00442     ep->setData01(toggle == 0 ? DATA0 : DATA1);
00443 }
00444 
00445 uint8_t HC::slot = 0x00;
00446 
00447 HC::HC() {
00448     static const int start = 1;
00449     uint8_t mask = (1<<start);
00450     for(int i = start; i < 8; i++, mask <<= 1) {
00451         if (!(slot & mask)) {
00452             slot |= mask;
00453             _ch = i;
00454             return;
00455         }
00456     }
00457     _ch = 0; // ERROR!!!
00458 }
00459 
00460 HC::HC(int ch) {
00461     _ch = ch;
00462     slot |= (1<<_ch);
00463 }
00464 
00465 HC::~HC() {
00466     slot &= ~(1<<_ch);
00467 }
00468 
00469 HAL_StatusTypeDef HC::Init(uint8_t epnum, uint8_t dev_address, uint8_t speed, uint8_t ep_type, uint16_t mps) {
00470     _ep_addr = epnum;
00471     _ep_type = ep_type;
00472     return HAL_HCD_HC_Init(&hhcd_USB_OTG_FS, _ch,
00473                            epnum, dev_address, speed, ep_type, mps);
00474 }
00475 
00476 HAL_StatusTypeDef HC::SubmitRequest(uint8_t* pbuff, uint16_t length, bool setup) {
00477     uint8_t direction = (_ep_addr & 0x80) ? DIR_IN : DIR_OUT;
00478     if (_ep_type == EP_TYPE_CTRL) {
00479         HCD_HCTypeDef* hc = &hhcd_USB_OTG_FS.hc[_ch];
00480         if (setup) {
00481             hc->data_pid = HC_PID_SETUP;
00482             hc->toggle_out = 0;
00483         } else {
00484             if (direction == DIR_IN) {
00485                 if (hc->toggle_in == 0) {
00486                     hc->data_pid = HC_PID_DATA0;
00487                 } else {
00488                     hc->data_pid = HC_PID_DATA1;
00489                 }
00490             } else { // OUT
00491                 if (hc->toggle_out == 0) {
00492                     hc->data_pid = HC_PID_DATA0;
00493                 } else {
00494                     hc->data_pid = HC_PID_DATA1;
00495                 }
00496             }
00497         }
00498         hc->xfer_buff = pbuff;
00499         hc->xfer_len  = length;
00500         hc->urb_state = URB_IDLE;
00501         hc->xfer_count = 0;
00502         hc->ch_num = _ch;
00503         hc->state = HC_IDLE;
00504   
00505         return USB_HC_StartXfer(hhcd_USB_OTG_FS.Instance, hc, 0);
00506     }
00507     return HAL_HCD_HC_SubmitRequest(&hhcd_USB_OTG_FS, _ch,
00508                                     direction, _ep_type, 0, pbuff, length, 0);
00509 }
00510 
00511 HCD_URBStateTypeDef HC::GetURBState() {
00512     return HAL_HCD_HC_GetURBState(&hhcd_USB_OTG_FS, _ch);
00513 }
00514 
00515 HCD_HCStateTypeDef HC::GetState() {
00516     return HAL_HCD_HC_GetState(&hhcd_USB_OTG_FS, _ch);
00517 }
00518 
00519 uint32_t HC::GetXferCount() {
00520     return HAL_HCD_HC_GetXferCount(&hhcd_USB_OTG_FS, _ch);
00521 }
00522 
00523 void HC::SetToggle(uint8_t toggle) {
00524     if (_ep_addr & 0x80) { // IN
00525         hhcd_USB_OTG_FS.hc[_ch].toggle_in = toggle;
00526     } else { // OUT
00527         hhcd_USB_OTG_FS.hc[_ch].toggle_out = toggle;
00528     }
00529 }
00530 
00531 #endif
00532 
00533