|
Рабочий пример работы SL811 в режиме host'a |
|
|
|
Apr 10 2007, 15:14
|

Участник

Группа: Свой
Сообщений: 49
Регистрация: 29-03-06
Пользователь №: 15 592

|
Тема поднималась милион раз, но никто так и не удосужился запостить пример. Значит буду первым: Код #define MASTER_MODE 0x80
void SL811_Init(void) { SL811Write(cDATASet, 0xe0); //SOF Timeout Value SL811Write(cSOFcnt, 0x2e | MASTER_MODE); SL811Write(CtrlReg, 0x5); SL811Write(EP0Status, PID_SOF); SL811Write(EP0Counter, 0); //Set Endpoint Zero SL811Write(EP0Control, 0x01); //Start the SOF SL811Write(IntEna, INSERT_REMOVE); //USB-A, Insert/Remove, USB_Resume. SL811Write(IntStatus, INT_CLEAR); //Clear Interrupt enable status }
#define NO_ERROR 0 #define ERROR_TIMEOUT 1 #define ERROR_STALL 2 #define ERROR_OVERFLOW 3 #define ERROR_EP0_ERROR 4 #define ERROR_UNKNOWN 5
int SendData(void * pData, int DataSize) { unsigned char result, intr, remainder,timeout; SL811BufWrite(EP0_Buf,pData,DataSize);
SL811Write(EP0Status,(PID_SETUP | 0)); // PID + EP address SL811Write(EP0Counter,0); // USB address SL811Write(EP0Address,EP0_Buf); // buffer address, start with "data0" SL811Write(EP0XferLen,DataSize); // data transfer length SL811Write(IntStatus,INT_CLEAR); // clear interrupt status SL811Write(EP0Control,DATA0_WR);
timeout=10; while(1) { do { intr = SL811Read(IntStatus); // wait for interrupt to be done if((intr & USB_RESET) || (intr & INSERT_REMOVE)) //leave if device is removed return 1; } while (!(intr & USB_A_DONE)); // interrupt done !!! SL811Write(IntStatus,INT_CLEAR); // clear interrupt status result = SL811Read(EP0Status); // read EP0status register remainder = SL811Read(EP0Counter); // remainder value in last pkt xfer if (result & EP0_ACK) return 0; if (result & EP0_NAK) // NAK Detected { SL811Write(IntStatus,INT_CLEAR); // clear interrupt status, need to SL811Write(EP0Control,DATA0_WR); // re-arm and request for last cmd, IN token result = 0; // respond to NAK status only } if (result & EP0_TIMEOUT) // TIMEOUT Detected { if(timeout) { timeout--; } else return ERROR_TIMEOUT; // exit on the timeout detected SL811Write(IntStatus,INT_CLEAR); // clear interrupt status, need to SL811Write(EP0Control,DATA0_WR); // re-arm and request for last cmd again } if (result & EP0_STALL) // STALL detected return ERROR_STALL; // for unsupported request. if (result & EP0_OVERFLOW) // OVERFLOW detected return ERROR_OVERFLOW; if (result & EP0_ERROR) // ERROR detected return ERROR_EP0_ERROR; } return ERROR_UNKNOWN; }
int GetReply(void * pData, int DataSize) { unsigned char result, intr, remainder,timeout; SL811Write(EP0Status,(PID_IN | 0)); // PID + EP address SL811Write(EP0Counter,0); // USB address SL811Write(EP0Address,EP0_Buf); // buffer address, start with "data0" SL811Write(EP0XferLen,DataSize); // data transfer length SL811Write(IntStatus,INT_CLEAR); // clear interrupt status SL811Write(EP0Control,DATA0_RD); timeout=10; while(1) { do { intr = SL811Read(IntStatus); // wait for interrupt to be done if((intr & USB_RESET) || (intr & INSERT_REMOVE)) //leave if device is removed return 1; } while (!(intr & USB_A_DONE)); // interrupt done !!! SL811Write(IntStatus,INT_CLEAR); // clear interrupt status result = SL811Read(EP0Status); // read EP0status register remainder = SL811Read(EP0Counter); // remainder value in last pkt xfer if (result & EP0_ACK) { if(remainder!=DataSize) { SL811BufRead(EP0_Buf, pData, DataSize); return 0; } } if (result & EP0_NAK) // NAK Detected { SL811Write(IntStatus,INT_CLEAR); // clear interrupt status, need to SL811Write(EP0Control,DATA0_WR); // re-arm and request for last cmd, IN token result = 0; // respond to NAK status only } if (result & EP0_TIMEOUT) // TIMEOUT Detected { if(timeout) { timeout--; } else return ERROR_TIMEOUT; // exit on the timeout detected SL811Write(IntStatus,INT_CLEAR); // clear interrupt status, need to SL811Write(EP0Control,DATA0_WR); // re-arm and request for last cmd again } if (result & EP0_STALL) // STALL detected return ERROR_STALL; // for unsupported request. if (result & EP0_OVERFLOW) // OVERFLOW detected return ERROR_OVERFLOW; if (result & EP0_ERROR) // ERROR detected return ERROR_EP0_ERROR; } return ERROR_UNKNOWN; }
unsigned char Buffer[0x64]; void testSL811(void) { int error; SetupPKG pkg; pkg.bmRequest=0x80; pkg.bRequest=0x06; pkg.wValue=0x200; pkg.wIndex=0x00; pkg.wLength=0xFF00; SL811ClockInit(); SL811_Init(); error=SendData(&pkg,sizeof(pkg)); if (!error) { error=GetReply(Buffer,0x9); } } Код не идеальный, надо доделывать функцию чтения. Он инитит хост в режиме low-speed и позволяет вам послать SETUP пакет GET_DESCRIPTOR и вычитать 9-байтов ответа от Slave устройства. Все нехватающие функции и define есть в cy3662/EZ811 development kit'e. Его можно взять вот тут
|
|
|
|
|
 |
Ответов
(1 - 14)
|
Apr 18 2007, 17:28
|

Участник

Группа: Свой
Сообщений: 49
Регистрация: 29-03-06
Пользователь №: 15 592

|
Я понял как заставить работать пример из EZ811 DK! У них там неправильный endian в VendorCmd(). Вот правильный: Код setup.bmRequest = bReq; setup.bRequest = bCmd; setup.wValue = WordSwap(wValue); setup.wIndex = WordSwap(wIndex); setup.wLength = wLen;
Сообщение отредактировал Hexxx - Apr 18 2007, 17:29
|
|
|
|
|
Apr 19 2007, 14:59
|

Участник

Группа: Свой
Сообщений: 49
Регистрация: 29-03-06
Пользователь №: 15 592

|
И все таки он глючит на чтении. Люди помогите, уже 2 недели бьюсь не могу понять как должно работать чтение. Как я делаю: Инициализирую SL811 в режим Full Speed: Код SL811Write(cSOFcnt,0xAE); // Set up host & full speed direct and SOF cnt SL811Write(cDATASet,0xE0); // SOF Counter Low = 0xE0; 1ms interval SL811Write(CtrlReg,0x05); // Setup 48MHz and SOF enable
SL811Write(EP0Status,0x50); // Setup SOF Token, EP0 SL811Write(EP0Counter,0x00); // reset to zero count SL811Write(EP0Control,0x01); // start generate SOF or EOP
SL811Write(IntStatus,INT_CLEAR); Шлю запрос на получение дескриптора конфигурации: Код SL811BufWrite(EP0_Buf,pData,DataSize); SL811Write(EP0Status,(PID_SETUP | 0)); SL811Write(EP0Counter,0); // USB address SL811Write(EP0Address,EP0_Buf); // buffer address, start with "data0" SL811Write(EP0XferLen,DataSize); // data transfer length SL811Write(IntStatus,INT_CLEAR); // clear interrupt status SL811Write(EP0Control,sDATA0_WR); Дальше жду пока закончится отправка и читаю статус: Код do { intr = SL811Read(IntStatus); // wait for interrupt to be done if((intr & USB_RESET) || (intr & INSERT_REMOVE)) //leave if device is removed return ERROR_DISCONNECT; } while (!(intr & USB_A_DONE)); // interrupt done !!! SL811Write(IntStatus,INT_CLEAR); // clear interrupt status status = SL811Read(EP0Status); // read EP0status register Возращается (status & EP0_ACK)==EP0_ACK. Т.е. с отправкой все ok. Далее читаю ответ. Я в снифере на компе поглядел, что должно прийти 0x43 байта. Размер EP0_Buf= 0x40 байт. Поэтому пытаюсь читать 0x40 байт: Код SL811Write(EP0Status, (PID_IN | 0)); // PID + EP address SL811Write(EP0Counter, 0); // USB address SL811Write(EP0Address, EP0_Buf); // buffer address, start with "data0"
if (ReqProc.BufferSize > 0x40) SL811Write(EP0XferLen, 0x40); else SL811Write(EP0XferLen,BufferSize); // data transfer length SL811Write(IntStatus, INT_CLEAR); // clear interrupt status SL811Write(EP0Control, sDATA0_RD); Снова жду результата: Код do { intr = SL811Read(IntStatus); // wait for interrupt to be done if((intr & USB_RESET) || (intr & INSERT_REMOVE)) //leave if device is removed return ERROR_DISCONNECT; } while (!(intr & USB_A_DONE)); // interrupt done !!! SL811Write(IntStatus,INT_CLEAR); // clear interrupt status status = SL811Read(EP0Status); // read EP0status register Опять возращается (status & EP0_ACK)==EP0_ACK. Т.е. вроде как прочитало. Читаю сколько там осталось дочитать: Код remainder = SL811Read(EP0Counter); remainder = 0x30, получается что недочитано 0x30 байт! Что делать дальше? Как их дочитать? Почему оно их недочитало? В примере из EZ811 DK они вообще такие пакеты скипают. Пробовал ради интереса прочитать то что лежит в EP0_Buf. Там лежит 0x10 байт, правильных, таких же как я видел в снифере на компе, а дальше мусор. Еще в примере из EZ811 DK они зачем-то переключают буферы когда читают большой кусок, зачем? И последнее, что такое payload? Как его определяют?
|
|
|
|
|
Apr 23 2007, 12:40
|

Участник

Группа: Свой
Сообщений: 49
Регистрация: 29-03-06
Пользователь №: 15 592

|
Отвечает Александр Друзь! Payload - это масимальный объем информации, который можно переслать/прочитать за 1 раз. Регистр EP0Counter - возвращает сколько байт было недочитано. Причем, число которое оттуда возвращается - signed! То есть если вы прочитали EP0Counter, а там 0xFC, это означает что не прочитано -4 байта. То есть вы захотели прочитать 0xC байт а девайс вам ответил 0x10-ю байтами. Получатеся, что еще 4 байта не было вычитано, хотя они есть. А если вы захотели прочитать 0xC, а девайс вам вернул 0x8 байт, то EP0Counter будет = 4. Т.е. вы запросили на 4 байта больше чем ответил девайс. Как узнать размер Payload для EP0? Payload обычно можно узнать запросив DEVICE descriptor. Но как его узнать если девайс говорит NAK на запрос DEVICE descriptor'a? Экспериментальным путем. Даже если девайс не поддерживает запрос Device descriptor'a, он поддерживает запрос на CONFIGURATION descriptor в любом случае. Обычно тут девайс выдает большой объем информации. Пробуйте читать ответ и смотрите сколько байт будет недочитано. Начните с 8 и увеличивайте кратно 8: 8, 16, 24, 32, 64. При одном из значений Payload, EP0Counter будет == 0. Это значение и есть payload. Фишка с чтением ответов девайса, длина которых > payload. Девайс действительно не даст вам прочесть данных больше чем payload, поэтому надо будет сделать еще N чтений. Но! Не пытайтесь дебажить код многократного чтения. Там дается очень короткий промежуток времени для дочитывания остальной части ответа. Когда пытаешься дебажить - первая часть читается нормально, а остальные так и не вычитываются. Переключение буферов делается для быстроты работы, в один мы читаем с USB, а из второго мы считываем то, что было уже прочитано из USB при предидущем чтении. Про то как надо делать переключение буферов описано в Application Notes см. "double buffer" Пример в EZ811 DK реально работоспособный. Очень важно делать speed_detect(). P.S. Почитал Application Notes по SL811. Много полезного. Приатачил.
Сообщение отредактировал Hexxx - Apr 23 2007, 12:47
|
|
|
|
|
May 10 2007, 15:18
|

Группа: Участник
Сообщений: 5
Регистрация: 10-05-07
Пользователь №: 27 632

|
Я решил так: int Read(unsigned char *buff) { unsigned char status; unsigned char bytesNotRead; int read = 0; for (int i = 0; i < 1000; ++i) { if ( DataRW(USB_DEVICE_ZERO, EpIn, EpInSize, EpInSize, &buff[read]) ) { GetXferInfo(&bytesNotRead, &status); if ( status & EP0_ACK ) { read += EpInSize - bytesNotRead; } if ( (0 == bytesNotRead) && (0 != read) ) { break; } } } return (read) ? read : -1; } Твоё мнение? Но не помогает. Цикл всё равно выполняется все 1000 раз а кусок буфера может прийти и позднее. А ответы действительно приходят кусками  Причём о том что должны быть ещё не узнать никак. Буду пробывать использовать стоповые байты  вместо if ( (0 == bytesNotRead) && (0 != read) ) { break; }
|
|
|
|
|
May 11 2007, 13:17
|

Участник

Группа: Свой
Сообщений: 49
Регистрация: 29-03-06
Пользователь №: 15 592

|
Я тут тоже по этому вопросу мучаю разных людей. Один мне на примере АТ команд для мобил вот что ответил:
> If the data of one package is less than payload size, it means cellphone has no other data to return.
т.е. если в количество непрочитаных байт(remainder) != 0, значит телефон еще не начал отвечать.
> If the data of one package is equal to payload size. It means cellphone has more data, or has no more data. You should read the endpoint 0x8a again.
Если количество непрочитаных байт == 0 (remainder), значит надо вычитать те данные, которые есть IN endpoint'е, а потом пытаться читать еще, чтобы проверить это все или нет.
> If cellphone return ACK, you should receive the following data. Если когда мы прочитали повторно, девайс сказал ACK - вычитываем то что есть, и читаем снова.
> If cellphone return NAK, it means cellphone has no other data to return by now. Если девайс сказал NAK - данные закончились.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|