Re: STM32 и USB (практика)
Добавлено: Сб июн 04, 2016 20:17:46
Togle это инвертирование при записи лог.1.
Да, забыл. Тут все верно. Если речь идет про состояние после резета, то регистр девственно чист. 0 и все. Вот тут-то мы записывая 11 и получим 11.isx писал(а):Ошибка была в предыдущем примере. Исправил, но смысл не поменялся....\
Пример с USB->EP0R = USB->EP0R | USB_EP_RX_VALID.
USB_EP_RX_VALID = 0х3000 = 0b0011000000000000. Так и получается значение VALID в RX
Код: Выделить всё
USB->EP0R |= USB_EP_TX_NAK; // Готовы к передаче, но данных для передачи нет
USB->EP0R |= USB_EP_RX_VALID; // К приему готов
Почитайте про запросы USB, я Вам тоже об этом писал. Вы задали банальный вопрос, говорящий о том что нет совсем представления как работает USB.isx писал(а): Для того, чтобы произошло прерывание пользовательский разъем USB нужно ПОДКЛЮЧАТЬ при ЗАПУЩЕННОЙ отладке.
Да, так.isx писал(а):Подскажите пожалуйста, как отправить пакет нулевой длины? Нужно USB_COUNT0TX выставить в ноль и USB_EP_TX в VALID. Тогда если хост просит ответить восьмью байтами то нужно USB_COUNT0TX сделать в 8 байт?
Код: Выделить всё
if (USB->ISTR & USB_ISTR_CTR)
{
USB->CNTR &= ~USB_EP_CTR_RX;
switch (*(__IO uint32_t*)(0x400060C1))
{
case 0x6:
for (i = 0; i < 17; i++)
{
*(__IO uint32_t*)(0x40006000 + i) = Virtual_Com_Port_DeviceDescriptor[i];
}
break;
}
} Код: Выделить всё
//Функция заполнения буфера отправки
void Buffer_Fill_Tx (uint8_t NumEP, uint8_t *Desc,uint8_t Len){ //NumEP -номер точки, Desc - массив байтов для отрпавки. Len - длина массива
uint16_t *pCount, *pTXBuf;
uint8_t i;
pTXBuf=0x40006000+NumEP*0x10; //адрес начало буфера TX
pCount=0x40006004+NumEP*0x10; //адрес COUNTn_TX
pTXBuf=*pTXBuf*2+0x40006000;
*pCount=Len;//длина пакета
for (i=0;i<Len;i+=2) pTXBuf[i]=Desc[i]+(Desc[i+1]<<8); //заполним буфер данными
}Код: Выделить всё
switch ((ConfigPacket.bmRequestType << 8 ) | (ConfigPacket.bRequest)) {
case 0x8006:{//ЗАПРОС ДЕСКРИПТОРА
//выбор типа дискриптора
switch(ConfigPacket.wValue) {
case 0x0100:{//Запрос дескриптора устройства
Buffer_Fill_Tx (0,Device_Descriptor,18); //заполнение буфера отправки
Set_Status_EPR(0,Valid,TX); // отправим дескриптор устройста,
break;}
case 0x0200:
...
...
...Код: Выделить всё
pTXBuf[i]=Desc[i]+(Desc[i+1]<<8)Который день пытаюсь реализовать прерывание по событию присоединения к шине USB (то, что вы Z_h_e идентифицируете как событие SE0)-Сначала инициализируется модуль USB. просто вкючаете, подкючаете генератор и т.д.
- По событию SE0 (воткнули девайс в комп) инициализируете нужные регистры, это событие кстати сбросит их в начальное состояние само.
-Затем устанавливаете в регистре EP0 VALID RX, т.е. МК готов принять данные для нулевой точки.
-Возникает прерывание об успешной транзакции. Расшифровываете и понимаете что что то получили.
- читаете что лежит в буфере приема, там будет запрос дескриптора устройства.
-ложите в буфер отправки дескриптор устройства и выставляете в регистре EP0 VALID TX и контроллер сам все отправит.
-после события об успешной отправки опять переводите МК в состояние в готов принять.
Код: Выделить всё
int main(void)
{
__enable_irq ();
//*****Настройка тактирования
//сброс системы тактирования
RCC_DeInit();
//Включаем HSE
RCC->CR |= RCC_CR_HSEON;
//Ждем готовности HSE
while((RCC->CR & RCC_CR_HSERDY) == 0) {}
//Предделитель AHB
RCC->CFGR |= RCC_CFGR_HPRE_0;
//Очистка регистра умножителя PLL
RCC->CFGR &= ~RCC_CFGR_PLLMULL;
//источник PLL от внешнего кварца
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;
//умножитель PLL x6
RCC->CFGR |= RCC_CFGR_PLLMULL6;
//Включаем PLL
RCC->CR |= RCC_CR_PLLON;
//Ждем готовности PLL
while((RCC->CR & RCC_CR_PLLRDY) == 0) {}
//очистка регистра SW
RCC->CFGR &= ~RCC_CFGR_SW;
//выбор источника тактирования PLL
RCC->CFGR |= RCC_CFGR_SW_1;
//Ожидание включения PLL
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {}
//*********************************************************
//Включим тактирование - порт A, B,C и альтернативного режима
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN|RCC_APB2ENR_AFIOEN;
// НОЖКА C9
GPIOC->CRH &= ~GPIO_CRH_CNF12_0 & ~GPIO_CRH_CNF12_1;
GPIOC->CRH |= GPIO_CRH_MODE12;
GPIOC->ODR |= GPIO_ODR_ODR12;
Код: Выделить всё
//делитель USB равен 1
RCC->CFGR |= RCC_CFGR_USBPRE;
//Разрешаем USB
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
//Очистка флагов USB
USB->ISTR = 0;
USB->CNTR = 0;
//Разрешаем прерывания
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_SetPriority (USB_LP_CAN1_RX0_IRQn, 2);
NVIC_EnableIRQ(USBWakeUp_IRQn);
//настройка прерываний от перефирии
EXTI->RTSR |= EXTI_RTSR_TR18; // прерывание №18
EXTI->IMR |= EXTI_IMR_MR18; // прерывание по выводам
EXTI->EMR |= EXTI_EMR_MR18; // прерывание по WU
USB->CNTR &= ~USB_CNTR_PDWN; //подаем питание
USB->CNTR &= ~USB_CNTR_FRES; //Включаем тактирование
//Настройка прерываний
USB->CNTR |= USB_CNTR_CTRM;
USB->CNTR |= USB_CNTR_WKUPM;
USB->CNTR |= USB_CNTR_SUSPM;
USB->CNTR |= USB_CNTR_RESETM;
Код: Выделить всё
void USB_LP_IRQHandler(void)
{
//Ждем события
if ((USB->ISTR & USB_ISTR_SUSP))
{
//какой-то код
}
}Спасибо! Я уже сам дошел до этого. На прерывания отзывается. Код немного подправил. Теперь первый РЕСЕТ (по сбросу FRES) игнорируется. Он мне без надобности (пока так). Регистр CNTR настраиваю отдельно. Далее теоретически следует определить момент присоединения девайса к шине хоста. Как это определить.?isx писал(а):А прерывание у вас точно правильно обозвано?
В моем файле с дефайнами (на stm32f1x) оно определено как USB_LP_CAN1_RX0_IRQn. Тогда и прерывание следовало бы обозвать как void USB_LP_CAN1_RX0_IRQnHandler(void)....
Это определит хаб, увидев что одна из линий данных "подтянулась" (воткнули разъем). Скажет об этом хосту, хост пошлет сброс. Это и есть момент подключения.Serg1987 писал(а):Далее теоретически следует определить момент присоединения девайса к шине хоста. Как это определить.?
Код: Выделить всё
switch (*(__IO uint32_t*)(0x400060C1))
{
case 0x6:
for (i = 0; i < 16; i+=2)
{
TXBuff = Virtual_Com_Port_DeviceDescriptor[i] + (Virtual_Com_Port_DeviceDescriptor[i+1] << 8);
*(__IO uint32_t*)(0x40006080 + i) = TXBuff;
}
USB->EP0R |= USB_EP_TX_VALID;
break;
}
Код: Выделить всё
USB->EP0R |= USB_EP_TX_VALID;Код: Выделить всё
switch (*(__IO uint32_t*)(0x400060C1))
{
case 0x6:
for (i = 0; i < 18; i+=2)
{
TXBuff = Virtual_Com_Port_DeviceDescriptor[i] + (Virtual_Com_Port_DeviceDescriptor[i+1] << 8);
*(__IO uint16_t*)(0x40006080 + i*2) = TXBuff;
}
*(__IO uint32_t*)(0x40006004) = 0x0012;
USB->EP0R |= USB_EP_TX_VALID;
test1 = USB->EP0R |= USB_EP_TX_VALID;
USB->EP0R |= USB_EP_RX_VALID;
break;
}