Микроконтроллеры

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Микроконтроллеры » Архив » USB интерфейс в STM32F103


USB интерфейс в STM32F103

Сообщений 1 страница 30 из 99

1

USB full-speed device interface - это по сути контроллер в контроллере, самостоятельно выполняющий все низкоуровневые операции USB-протокола.
С точки зрения программы в МК, USB представляется как набор буферов (в терминологии USB - endpoints) для обмена данными и регистров для управления этими буферами и процессом в целом.
Обмен данными происходит в режиме мастер-слейв (мастер - хост, слейв - девайс), по своей инициативе девайс никаких данных не передаёт - только по запросу от хоста.
Больше того, МК вообще не передаёт данные, а только готовит их для передачи - заполняет буфер и устанавливает флажки готовности, а хост потом "забирает" эти данные когда ему вздумается.

Весь процесс выглядит примерно так.
Если хост захочет что-то получить от девайса, то он будет делать периодические запросы с указанием из какого конкретно endpoint-буфера он хочет получить данные.
Если МК уже выставил готовность endpoint к передаче, то контроллер USB сам, без участия процессора МК, передаст хосту данные и сбросит флажки готовности endpoint.
Если же готовность enpoint к передаче не была выставлена, то хост будет повторять попытки.

И в обратную сторону.
Если хост захочет что-то передать девайсу, то он будет делать периодические запросы, предлагая принять данные и указывая при этом для какого конкретно endpoint-буфера эти данные предназначены.
Если МК уже выставил готовность endpoint к приёму, то контроллер USB сам, без участия процессора МК, примет от хоста данные и сбросит флажки готовности endpoint.
Если же готовность endpoint к приёму не была выставлена, то хост будет повторять попытки.

Для управления endpoint-буферами предназначены регистры EPnR.
Их восемь штук, они все одинаковые, и поскольку endpoints в USB двунаправленные, то каждый регистр может управлять двумя буферами - на приём (RX) и на передачу (TX).

http://s5.uploads.ru/OQ7Kw.png

Я выделил жёлтеньким две почти одинаковые группы битов, отличающиеся только тем, что первая управляет приёмником, а вторая - передатчиком.
То, что я выше называл флажками готовности - это биты STAT_{RX|TX} (status bits), вот их значения:
00 - DISABLED - буфер вообще не работает или просто не существует;
01 - STALL - буфер не работает для текущего запроса, повторно запрашивать бесполезно;
10 - NAK - буфер временно не готов, но можно и нужно запрашивать повторно;
11 - VALID - буфер готов.
Выставить готовность - это установить статус VALID, а по окончании приёма-передачи (в терминологии USB - транзакции) контроллер USB сам сбросит готовность - установит статус NAK.

Биты CTR_{RX|TX} (correct transfer) - признак окончания транзакции, устанавливается контроллером USB когда данные приняты или переданы, и МК может перечитать приёмный буфер или перезаписать передающий.
Биты DTOG_{RX|TX} (data toggle) контроллер USB обычно благополучно разруливает сам, и я не буду затуманивать текст лишними деталями, скажу только, что этот бит надо сбрасывть в начале транзакций.

Важная особенность всех этих битовых полей - спец способы установки, обозначенные на картинке:
rc_w0 - только сброс - запись нуля записывает ноль, запись единицы игнорируется;
t - переключение (toggle) - запись единицы инвертирует бит, запись нуля игнорируется.
IMHO, проще всего устанавливать эти поля исключающим "или".
Вот табличка для toggle-логики:

Код:
Было Запись Стало
0    0      0
0    1      1
1    0      1
1    1      0

Видно, что {Запись} == {Было}^{Стало}, т.е. чтобы выставить нужные значения t-битов:
EPnR ^= {нужные значения t-битов}

Биты EA - endpoint адрес.
Endpoints в USB адресуются от нуля до 15.
Казалось бы, зачем указывать адрес, если регистры EPnR уже сами пронумерованы?
Фокус в том, что номер регистра EPnR соответствует не адресу endpoint, а порядковому номеру пары буферов, которыми этот регистр управляет.
Теоретически, восемь регистров EPnR могут быть настроены на работу с любыми восемью адресами из 16, но практически лучше настраивать так, чтобы номера регистров совпадали с адресами.

Биты EP_TYPE - endpoint type.
00 - bulk
01 - control
10 - isochronous
11 - interrupt
Почитать про типы в популярном изложении (да и вообще про USB) можно, например, тут - http://www.usbmadesimple.co.uk/index.html или тут - http://www.beyondlogic.org/usbnutshell/usb1.shtml

Бит SETUP - дополнительный признак окончания транзакции для endpoint с нулевым адресом и типом control.
Endpoint c нулевым адресом используется в USB не только для обмена данными, но и для управления девайсом, в частности для первоначальной конфигурации девайса хостом (enumeration).
Бит SETUP устанавливается контроллером USB, если закончившаяся транзакция была транзакцией управления, а сбрасывается по сбросу бита CTR_RX.

Пример функции приёма данных.

Код:
int USBGet (uint16_t* a) {
    uint32_t r = USB->EP1R ^ 0x3000;
    if (r & 0xB000) {
        for (int i = 0; i < 32; i++) a[i] = (uint16_t) (*USBRXD1)[i];
        USB->EP1R = (r & ~0xC070) | 0x80;
        return 0;  // ok
    } else {
        return 1;  // fail
    }
}

Пример функции передачи (а точнее - подготовки передачи) данных.

Код:
int USBPut (uint16_t* a) {
    uint32_t r = USB->EP1R ^ 0x30;
    if (r & 0xB0) {
        for (int i = 0; i < 32; i++) (*USBTXD1)[i] = (uint32_t) a[i];
        USBTABLE->tx1cnt = 64;
        USB->EP1R = (r & ~0x70C0) | 0x8000;
        return 0;  // ok
    } else {
        return 1;  // fail
    }
}

В этих примерах кроме манипуляций с регистром EP1R фигурируют буферы данных (*USBRXD1 и *USBTXD1) и счётчик байтов (USBTABLE->tx1cnt).

Отредактировано vt340 (2017-04-26 08:59:59)

2

Для endpoint-буферов у контроллера USB есть собственная RAM 512 байт.
Эта RAM мэппируется в адресное пространство МК таким вот странным способом - в младшие 16 бит 32-битных слов, начиная с адреса 0x40006000.

Код:
Адресация в МК  Адресация в USB-контроллере
0x40006000:     0x0000 0x0001 ------ ------
0x40006004:     0x0002 0x0003 ------ ------
0x40006008:     0x0004 0x0005 ------ ------
0x4000600C:     0x0006 0x0007 ------ ------
...

Расположение и размер буферов не фиксированы, а должны задаваться специальной таблицей, состоящей из 32-х 16-битных слов (по четыре слова на каждый из восьми EPnR).
Cама таблица должна находиться в этой же RAM, расположение таблицы тоже не фиксировано, а задаётся регистром BTABLE.
Если в BTABLE оставить ноль (что обычно и делают), то таблица будет начинаться с нулевого адреса.

Структура таблицы (каждая строчка - 16-битное слово).

Код:
Адрес TX-буфера EP0
Счётчик байт TX-буфера EP0
Адрес RX-буфера EP0
Cчётчик байт RX-буфера EP0
Адрес TX-буфера EP1
Счётчик байт TX-буфера EP1
Адрес RX-буфера EP1
Cчётчик байт RX-буфера EP1
...

Адреса буферов - это адреса в адресном пространстве контроллера USB, а не МК, и они должны быть чётными.
Счётчик байт TX-буфера задаёт сколько байт из буфера нужно передать.

Счётчик байт RX-буфера содержит в старших битах код размера буфера, а в младших - кол-во принятых байт.
http://sd.uploads.ru/c0xg3.png
http://s3.uploads.ru/fqQhw.png

Пример инициализации endpoint-буферов.

Код:
typedef struct {
    uint32_t tx0adr, tx0cnt, rx0adr, rx0cnt;
    uint32_t tx1adr, tx1cnt, rx1adr, rx1cnt;
} usbtable_t;

typedef uint32_t uint32x32_t[32];

#define USBTABLE  ((usbtable_t*) 0x40006000)
#define USBTXD0  ((uint32x32_t*) 0x40006100)
#define USBRXD0  ((uint32x32_t*) 0x40006180)
#define USBTXD1  ((uint32x32_t*) 0x40006200)
#define USBRXD1  ((uint32x32_t*) 0x40006280)

*USBTABLE = (usbtable_t) {
    128, 0, 192, 0x8400,
    256, 0, 320, 0x8400
};

3

Кроме регистров EPnR, управляющих своими endpoint-буферами, в USB-контроллере есть пара регистров для управления процессом в целом:
CNTR (control) - маски прерываний и биты управления режимами работы;
ISTR (interrupt status) - флажки состояний и идентификатор источника прерывания (поскольку вектор прерывания один для всех источников).
http://sh.uploads.ru/ibud7.png
Если не использовать прерывания (которые и по сути зло, а для USB - абсолютное зло) и засыпание-просыпание (suspend-wakeup) девайса, то понадобятся только три бита (я выделил их жёлтеньким):
PWDN - запись нуля включает аналоговую часть USB-контроллера, запись единицы - выключает;
FRES - запись единицы ресетит USB-контроллер;
RESET - устанавливается USB-контроллером в единицу, когда хост выставляет на шине спец состояние reset (D+ и D- в нуле на 10 мс), сбрасывается в ноль программой МК.

По ресету USB-контроллера все регистры EPnR автоматически сбрасываются, и их надо устанавливать заново.
Пример реакции на reset.

Код:
if (USB->ISTR_b.RESET) {
    USB->CNTR = 0;
    USB->ISTR = 0;
    USB->EP0R_b.EA = 0; USB->EP0R_b.EP_TYPE = 1;  // ep0 control
    USB->EP1R_b.EA = 1; USB->EP1R_b.EP_TYPE = 0;  // ep1 bulk
    USB->EP0R ^= 0xB0A0;  // rx0:valid tx0:nak
    USB->EP1R ^= 0xB0A0;  // rx1:valid tx1:nak
    USB->DADDR = 0x80;
}

В этом примере есть регистр DADDR, про который я ещё не писал.
Это регистр для USB-адреса, который хост присваивает и присылает девайсу при подключении.
Биты 0-6 этого регистра используются для адреса (USB-адреса семибитные), а седьмой бит - для разрешения (единицей) или запрета (нулём) всех транзакций.
До того как хост пришлёт девайсу адрес, у девайса должен быть нулевой адрес, поэтому по ресету в DADDR записывается 0x80.

Итого, 12 регистров (EP0R-EP7R, BTABLE, CNTR, ISPR, DADDR) и таблица в RAM - это всё, что необходимо знать об USB-контроллере для работы с USB.

Отредактировано vt (2019-10-10 15:56:23)

4

vt340, спасибо за полезную информацию, как раз начал разбираться с usb на stm32f042f6, очень помогаете. Пока дошел до энумерации, на логическом анализаторе вижу, что приходит пакет SETUP и следом за ним GET_DESCRIPTOR. Прерывание CTR вызывается, но пока не особо понятно как на него реагировать. В отладчике в прерывании смотрю значения в массиве USBRXD0 но ничего похожего как на лог. анализаторе не вижу. Знаю, что надо послать первые 8 байт дескриптора устройства, но на что ориентироваться - на флаг SETUP в EP0R или искать в USBRXD0 - GET_DESCRIPTOR? С этим пока не разобрался.
И еще вопрос, почему прерывания в USB такое зло?

Отредактировано sobs (2017-04-22 22:09:36)

5

sobs написал(а):

vt340, спасибо за полезную информацию, как раз начал разбираться с usb на stm32f042f6, очень помогаете. Пока дошел до энумерации, на логическом анализаторе вижу, что приходит пакет SETUP и следом за ним GET_DESCRIPTOR. Прерывание CTR вызывается, но пока не особо понятно как на него реагировать. В отладчике в прерывании смотрю значения в массиве USBRXD0 но ничего похожего как на лог. анализаторе не вижу. Знаю, что надо послать первые 8 байт дескриптора устройства, но на что ориентироваться - на флаг SETUP в EP0R или искать в USBRXD0 - GET_DESCRIPTOR? С этим пока не разобрался.
И еще вопрос, почему прерывания в USB такое зло?

Отредактировано sobs (Вчера 22:09:36)

Привет,  sobs, у нас тут принято обращаться на ты
Анализатором ты видишь низкоуровневый протокол, которым занимается usb-контроллер
С точки зрения мк, setup-пакет это восемь байт, принятых в ep0, которые девайс должен разобрать и ответить хосту соответственно
По поводу прерываний - чтоб не обсуждать сферических коней в вакууме, если ты попробуешь детально расписать структуру программы с прерываниями (что, куда, когда и как передаётся, принимается, перекладывается, обрабатывается, как синхронизируется, какими флажками и т.п.), то я попробую на этом конкретном примере объяснить почему прерывания зло

6

vt340 написал(а):

Привет,  sobs, у нас тут принято обращаться на ты
Анализатором ты видишь низкоуровневый протокол, которым занимается usb-контроллер
С точки зрения мк, setup-пакет это восемь байт, принятых в ep0, которые девайс должен разобрать и ответить хосту соответственно
По поводу прерываний - чтоб не обсуждать сферических коней в вакууме, если ты попробуешь детально расписать структуру программы с прерываниями (что, куда, когда и как передаётся, принимается, перекладывается, обрабатывается, как синхронизируется, какими флажками и т.п.), то я попробую на этом конкретном примере объяснить почему прерывания зло

На анализаторе вижу такую картину - идут 2 пакета, первый SETUP, второй DATA0. Вот структура этих пакетов, как мне их анализатор расшифровал:
1)
SYNC
PID SETUP
ADDR = 0x00, ENDP = 0x00
CRC OK
EOP
2)
SYNC
PID DATA0
bmRequestType = 0x80
bRequest=0x06 GET_DESCRIPTOR
wValue=0x0100
wIndex=0x0000
wLength=0x0040
CRC OK
EOP

Отладчиком не успеваю словить, флаг CTR тут 2 раза устанавливается?
Правильно ли я понимаю, что после установки флага CTR в ep0 будут следующие 8 байт:
bmRequestType = 0x80
bRequest=0x06 GET_DESCRIPTOR
wValue=0x0100
wIndex=0x0000
wLength=0x0040 ?
По прерываниям, я пока еще обмен не запустил, поэтому пока описать структуру программы не смогу. Но я пробую именно на прерываниях.
Извиняюсь за тупые вопросы.

Отредактировано sobs (2017-04-23 10:36:54)

7

sobs написал(а):

флаг CTR тут 2 раза устанавливается?)

Нет, на анализаторе ты видишь то, что получает usb-контроллер.
Он всё это декодирует, помещает 8 байт полезных данных во входной буфер ep0 и поднимает флаги ctr_rx и setup в ep0r.

sobs написал(а):

Правильно ли я понимаю, что после установки флага CTR в ep0 будут следующие 8 байт:
bmRequestType = 0x80
bRequest=0x06 GET_DESCRIPTOR
wValue=0x0100
wIndex=0x0000
wLength=0x0040 ?

Да, эти 8 байт

sobs написал(а):

По прерываниям, я пока еще обмен не запустил, поэтому пока описать структуру программы не смогу. Но я пробую именно на прерываниях.

Под программой я имею в виду обмен содержательными данными между девайсом и хостом, а не enumeration, которая только разовый эпизод.
И учитывай ещё, что хост может передавать-принимать пакеты со скоростью до 5 Мбит/с, т.е. до 10 пакетов по 64 байта в миллисекунду

Отредактировано vt340 (2017-04-23 11:21:00)

8

Уважаемые, какой анализатор пользуете?

9

У меня никакого нет, ты же знаешь, что я всё с помощью палки, верёвки и какой-то матери )

10

Думаю надо просто понимать все стадии настройки хоста с определенным типом устройства HID или CDC .
Для начала помогла вот эта статья Ссылка .

11

dosikus написал(а):

Уважаемые, какой анализатор пользуете?

Китайский клон saleae logic за 10$ с али.

Отредактировано sobs (2017-04-23 13:09:52)

12

sobs написал(а):

Китайский клон saleae logic за 10$ с али.
(Сегодня 18:09:52)

У меня такой же.
Решил посмотреть как мышка обменивается при подключении,но там только по линии D+ идет обмен при подключении и анализатор расшифровывать не хочет. А вот подключил к микроконтроллеру и весь обмен видно стало. Минус только окошечко маленькое и и искать среди кучи пакетов неудобно. К тому же при подключении хост начинает общаться с адресом 2 и потом понимает что такого нет начинает настройку по нулевому.

Первым передается дескрипт устройства, потом дается адрес устройству и начинается опрос остальных дескриптов.

http://s4.uploads.ru/t/rHZX4.png
http://sg.uploads.ru/t/4wDtF.png

Отредактировано CERGEI (2017-04-23 14:26:40)

13

CERGEI написал(а):

sobs написал(а):

    Китайский клон saleae logic за 10$ с али.
    (Сегодня 18:09:52)

У меня такой же.
Решил посмотреть как мышка обменивается при подключении,но там только по линии D+ идет обмен при подключении и анализатор расшифровывать не хочет. А вот подключил к микроконтроллеру и весь обмен видно стало. Минус только окошечко маленькое и и искать среди кучи пакетов неудобно. К тому же при подключении хост начинает общаться с адресом 2 и потом понимает что такого нет начинает настройку по нулевому.

Первым передается дескрипт устройства, потом дается адрес устройству и начинается опрос остальных дескриптов.

http://s4.uploads.ru/t/rHZX4.png
http://sg.uploads.ru/t/4wDtF.png

Отредактировано CERGEI (Сегодня 14:26:40)

Подпись автора

    Глаза боятся,а руки делают.

Согласен, искать не очень удобно, но хоть что-то)

14

vt340, можешь поделиться исходником с USB, если конечно есть, а то что-то я не так делаю. Заполняю USBTABLE, так

Код:
void USB_SetTable(){
	*(uint32_t*)0x40006000 = 128;
	*(uint32_t*)0x40006004 = 0;
	*(uint32_t*)0x40006008 = 192;
	*(uint32_t*)0x4000600C = 0x8400;
}

В отладчике вижу, что все верно
http://s1.uploads.ru/t/T0B57.jpg
Но как только срабатывает прерывание CTR, память как-будто портится
http://sf.uploads.ru/t/TaeAu.jpg
И по адресу 0x400060C0, где должен приемный буфер ep0, следующее содержимое
http://sd.uploads.ru/t/PthNp.jpg
Видно, что содержимое по адресам 0x400060C0 = 0x40006000 и 0x400060C8 = 0x40006008. Что-то тут не чисто.
Вот мой обработчик:

Код:
void USB_IRQHandler(){
	if (USB -> ISTR & USB_ISTR_RESET){
             USB -> ISTR &= ~USB_ISTR_RESET;
             USB_Reset();
	}
	if (USB -> ISTR & USB_ISTR_CTR){
             if ((USB -> EP0R & USB_EPnR_CTR_RX) && (USB -> EP0R & USB_EPnR_SETUP)){
    	          LED_ON;
    	          USB -> EP0R ^= USB_EPnR_STAT_RX_1 | USB_EPnR_STAT_TX_1;
             }
	}
}

Функция USB_Reset():

Код:
void USB_Reset(){
	USB -> BTABLE = 0;
	USB_SetTable();
	USB -> CNTR = 0;
	USB -> CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
	USB -> ISTR = 0;
	USB -> DADDR = USB_DADDR_EF;
	USB -> EP0R = USB_EPnR_EP_TYPE_0;
	USB -> EP0R ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX;
}

Функция main

Код:
int main(void)
{
	SetClockHSI48();
	RCC -> AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOFEN;
	RCC -> APB2ENR |= RCC_APB2ENR_SYSCFGEN;
	RCC -> APB1ENR |= RCC_APB1ENR_USBEN | RCC_APB1ENR_TIM14EN;

	SYSCFG -> CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
	USB_Reset();
	USB -> BCDR |= USB_BCDR_DPPU;     //Включаем подтяжку на D+
	NVIC_EnableIRQ(USB_IRQn);
	LED_OFF;
        while(1)
        {

        }
}

15

Вот полный пример и для девайса, и для хоста - https://yadi.sk/d/naqKh4e03EDEJU/STM32-USB/usb-vsc.zip

16

Или я дурак, или лыжи не едут) Уже голову сломал, вроде все сделал так, а оно не работает.
Итак, вот код

Код
Код:
#include <stm32f0xx.h>
#include "usb_defs.h"
#include "delay.h"

#define LED_ON    GPIOF -> BSRR = GPIO_BSRR_BS_0
#define LED_OFF    GPIOF -> BSRR = GPIO_BSRR_BR_0
#define LED_TOGGLE	GPIOF -> ODR ^= GPIO_ODR_0

void SetClockHSI48(){
	RCC -> CR2 |= RCC_CR2_HSI48ON;
	while (!(RCC -> CR2 & RCC_CR2_HSI48RDY));
	FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
	RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
	RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
	RCC -> CFGR |= RCC_CFGR_SW;
}

void TIM14_IRQHandler(){
	TIM14 -> SR &= ~TIM_SR_UIF;
	LED_OFF;
	TIM14 -> CR1 = 0;
}

typedef struct {
	uint32_t data[16];
} uint32x16_t;

typedef struct {
	uint32_t tx0addr, tx0cnt, rx0addr, rx0cnt;
	uint32_t tx1addr, tx1cnt, rx1addr, rx1cnt;
	uint32_t tx2addr, tx2cnt, rx2addr, rx2cnt;
	uint32_t tx3addr, tx3cnt, rx3addr, rx3cnt;
	uint32_t tx4addr, tx4cnt, rx4addr, rx4cnt;
	uint32_t tx5addr, tx5cnt, rx5addr, rx5cnt;
	uint32_t tx6addr, tx6cnt, rx6addr, rx6cnt;
	uint32_t tx7addr, tx7cnt, rx7addr, rx7cnt;
} usbtable_t;

#define USBTABLE	((usbtable_t*) 0x40006000)
#define USB_TX0    ((uint32x16_t*)0x40006100)
#define USB_RX0    ((uint32x16_t*)0x40006180)

void USB_Init(){
	RCC -> APB1ENR |= RCC_APB1ENR_USBEN;
	RCC -> APB2ENR |= RCC_APB2ENR_SYSCFGEN;
	RCC -> AHBENR |= RCC_AHBENR_GPIOAEN;

	SYSCFG -> CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
	USB -> CNTR = 0;
	USB -> CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
	USB -> ISTR = 0;

	USB -> BTABLE = 0;
	*USBTABLE = (usbtable_t) {
               128, 0, 192, 0x8400,
               256, 0, 320, 0x8400,
               384, 0, 448, 0x8400,
               512, 0, 576, 0x8400,
               640, 0, 704, 0x8400,
               768, 0, 832, 0x8400,
               896, 0, 960, 0x8400
	};

	USB -> DADDR = USB_DADDR_EF;

	USB -> EP0R |= USB_EPnR_EP_TYPE_0;
	USB -> EP0R ^= 0xB0A0;

	USB -> BCDR |= USB_BCDR_DPPU;
	NVIC_EnableIRQ(USB_IRQn);
}

void USB_IRQHandler(){
	if (USB -> ISTR & USB_ISTR_RESET){
             USB -> CNTR = 0;
             USB -> CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
             USB -> ISTR = 0;
             USB -> EP0R = USB_EPnR_EP_TYPE_0;
             USB -> DADDR = USB_DADDR_EF;
             USB -> EP0R ^= 0xB0A0;
	}
	if (USB -> ISTR & USB_ISTR_CTR){
             if ((USB -> EP0R & USB_EPnR_CTR_RX) && (USB -> EP0R & USB_EPnR_SETUP)){
    	         if ((USBTABLE -> rx0cnt & USB_COUNTn_COUNTn_RX) == 8) LED_ON;

    	         if (USB_RX0 -> data[0] == 0x680){
                       LED_ON;
    	         }
             }
             TIM14 -> CR1 = TIM_CR1_CEN;
	}
}

int main(void)
{
	SetClockHSI48();
	RCC -> AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOFEN;
	RCC -> APB1ENR |= RCC_APB1ENR_TIM14EN;

	USB_Init();

	GPIOF -> MODER = GPIO_MODER_MODER0_0;
	GPIOF -> PUPDR = 0;
	GPIOF -> OTYPER = 0;
	GPIOF -> OSPEEDR |= GPIO_OSPEEDER_OSPEEDR0;

	LED_OFF;

	TIM14 -> ARR = 200;
	TIM14 -> PSC = 48000 - 1;
	TIM14 -> DIER = TIM_DIER_UIE;
	NVIC_EnableIRQ(TIM14_IRQn);

        while(1)
        {

        }
}

Ставлю брейкпоинт сразу после *USBTABLE = (usbtable_t) {...}, вот картинка памяти
http://s2.uploads.ru/t/8OwdT.jpg
Видно, что записалось все верно. Теперь ставлю брейкпоинт в прерывание, сразу после if ((USB -> EP0R & USB_EPnR_CTR_RX) && (USB -> EP0R & USB_EPnR_SETUP)), включаю лог анализатор и запускаю. Вот скриншот анализатора

Снимок экрана

http://s2.uploads.ru/t/mvb3c.jpg

Содержимое памяти по адресу 0x40006000, где по идее ничего кроме rx0cnt поменяться не должно, а тут где должен быть tx0addr - запрос дескриптора 0x680, где rx0addr вообще 0xDDDD, а rx0cnt не изменилось, хотя должно быть 0x8408.
http://sh.uploads.ru/t/M9dFu.jpg
Зато по там где должен быть запрос дескриптора и остальные данные - мусор
http://sd.uploads.ru/t/0DRsk.jpg
Что я мог упустить? Уже 3й раз за сегодня референс перечитываю)
На всякий случай залил проект на  дропбокс
P.S. Так много endpoints создал уже от отчания, думал мало ли)

17

Если возник затык, не ломай голову,  а локализуй и изолируй проблему - выкинь всё до абсолютного минимума, добейся чтоб заработало и потом добавляй функционал
Извини за нравоучения, но это азбука )

18

vt340,  demo.exe падает на win7 64 . Пока запускаю только ее, без девайса...

19

Оно win32 (чтоб и в xp работало) я там подписывал вроде в readme
Попробуй 64-битную dll libusb взять с http://libusb.info там у них в бинарном архиве в папочке ms64
Если не прокатит то придётся на 64-битной версии tcc http://download.savannah.gnu.org/releases/tinycc/ перекомпилировать

Отредактировано vt340 (2017-04-24 11:16:06)

20

Прошел затык) Проблема была в том, что задание Buffer descriptor table в F0 отличается от F1.
В F1 доступ к полям таблицы 32 битный, из-за чего адреса в периферии и в памяти отличаются в 2 раза. Например в таблице устанавливаем адрес TX буфера равным 128, а для программы приемный буфер будет лежать уже со смещением 256 от 0x40006000.
В F0 же, 32 битный доступ к полям таблицы запрещен, вот цитата из референса The first packet memory location is located at 0x4000 6000. The buffer descriptor table entry associated with the USB_EPnR registers is described below. The packet memory should be accessed only by byte (8-bit) or half-word (16-bit) accesses. Word (32-bit) accesses are not allowed. И адресация в периферии совпадает с адресацией в памяти. Сбивало с толку то, что в отладчике некорректно отображаются эти адреса, например после записи

Код:
*(uint16_t*)0x40006000 = 128
*(uint16_t*)0x40006002 = 0

Судя по отладчику в памяти по адресу 0x40006000 лежит не 0x00800000, а 0x00800080, хотя если считывать в программе, то все там лежит как надо.
Теперь возникла проблема с тактированием. Когда делал плату, начитался что в stm32f042 есть высокостабильный внутренний генератор на 48 МГц и CRS (Clock Recovery System), который можно настроить на синхронизацию с USB SOF пакетами. Без CRS на анализаторе при ответе девайса на запрос PID IN шел Error Packet. Включил CRS с настройками по умолчанию, вместо Error Packer появился PID NAK, и даже 64 байта дескриптора пошли но видно что частота то увелививается, то падает. Из-за чего проскакивают Error Packet.

21

sobs написал(а):

Проблема была в том, что задание Buffer descriptor table в F0 отличается от F1.
В F1 доступ к полям таблицы 32 битный, из-за чего адреса в периферии и в памяти отличаются в 2 раза. Например в таблице устанавливаем адрес TX буфера равным 128, а для программы приемный буфер будет лежать уже со смещением 256 от 0x40006000.
В F0 же, 32 битный доступ к полям таблицы запрещен, вот цитата из референса The first packet memory location is located at 0x4000 6000. The buffer descriptor table entry associated with the USB_EPnR registers is described below. The packet memory should be accessed only by byte (8-bit) or half-word (16-bit) accesses. Word (32-bit) accesses are not allowed. И адресация в периферии совпадает с адресацией в памяти.

Если так, то пожалуй надо убирать из моих опусов упоминания о F0|L0, ну или проверять и править, но некогда сейчас, так что просто уберу наверно пока

Или ещё лучше, sobs, заводи тут рядом топик про F0 )

Отредактировано vt340 (2017-04-24 11:47:33)

22

Или ещё лучше, sobs, заводи тут рядом топик про F0 )

А есть ли смысл? Пока больше отличий не нашел.

23

sobs, то есть пример vt340 с правками под F0 заработал? Если не трудно выложи...

24

Заработала передача и прием, вот проект в запакованном и распакованном виде Ссылка. Светодиод на плате загорается, что говорит о правильном приеме. Сейчас проблема с тактовой частотой, на анализаторе вижу такую картину
http://sa.uploads.ru/t/yNlzI.jpg
Соответственно анализатор пишет Error Packet, но что интересно хост отвечает ACK, то есть он принял без ошибок. Вот сижу и думаю, может глюки анализатора? Внешнего кварца нет, работаю от внутреннего HSI48, CRS не помогает, хотя может не правильно настраиваю.

25

Теперь энумерация проходит, устройство определяется. Одно из двух, либо это глюки анализатора, либо хосты (пробовал и windows и linux) прощают такое "плавание" частоты)
Залил пример в туже ссылку. Продублирую еще раз Ссылка

26

Засел изучать USB вАААще , скоро присоединюсь .
Кстати кто подскажет анализатор софтовый на стороне ББ?

27

dosikus написал(а):

Засел изучать USB вАААще , скоро присоединюсь .
Кстати кто подскажет анализатор софтовый на стороне ББ?

Просто давно собирался, а тут как раз выходные.
Слышал про wireshark, но сам не пользовался.

28

Ладно, раз пошла такая пьянка, вот тогда расшифровка дескрипторов из примера
Хотел причесать потом для поста про enumeration, но когда я ещё соберусь, так что в сыром виде, выдранную прямо из ассемблера

device

Код:
.byte 18, 1    ,0,0  @ bLength, bDescriptorType
.word 0x110          @ bcdUSB
.byte 0, 0     ,0,0  @ bDeviceClass, bDeviceSubclass
.byte 0, 64    ,0,0  @ bDeviceProtocol, bMaxPacketSize0
.word 0x4444         @ idVendor
.word 1              @ idProduct
.word 1              @ bcdDevice
.byte 0, 0     ,0,0  @ iManufacturer, iProduct
.byte 0, 1     ,0,0  @ iSerialNumber, bNumConfigurations

configuration

Код:
.byte 9, 2     ,0,0  @ bLength, bDescriptorType
.word 32             @ wTotalLength
.byte 1, 1     ,0,0  @ bNumInterfaces, bConfigurationValue
.byte 0, 0xC0  ,0,0  @ iConfiguration, bmAttributes (self-powered)
.byte 0              @ bMaxPower
@ interface
.byte 9        ,0,0  @ bLength
.byte 4, 0     ,0,0  @ bDescriptorType, bInterfaceNumber
.byte 0, 2     ,0,0  @ bAlternateSetting, bNumEndpoints
.byte 0xFF, 0  ,0,0  @ bInterfaceClass, bInterfaceSubclass
.byte 0, 0     ,0,0  @ bInterfaceProtocol, iInterface
@ endpoint
.byte 7, 5     ,0,0  @ bLength, bDescriptorType
.byte 0x81, 2  ,0,0  @ bEndpointAddress (1 IN), bmAttributes (bulk)
.word 64             @ wMaxPacketSize
.byte 0              @ bInterval
@ endpoint
.byte 7        ,0,0  @ bLength
.byte 5, 1     ,0,0  @ bDescriptorType, bEndpointAddress (1 OUT)
.byte 2, 64    ,0,0  @ bmAttributes (bulk), wMaxPacketSize...
.byte 0, 0     ,0,0  @ ...wMaxPacketSize, bInterval

29

vt340, спасибо за пинки!
Начал читать документацию на USB как RM так и нутшелл попутно роя USB прослойку от MCD.
Чем дальше рою тем больше уверенности, что какую-то реализацию на плюсах за уши притянули к железу STM.

vt340, те значения что используешь  в поллинге, а sobs в прерывании , есть ли дефайны для них в природе ?
Кстати за тобой разжевывание о зле в прерываниях в USB. Или ты о том, что обработчик выходит довольно-таки затянутым?

Кстати а не замутишь тулзу для дескрипторов ?

sobs, глянул мельком  осцилл на F042 от tomeko https://tomeko.net/miniscope_v2f/index.php?lang=en
у него тот же инит HSI48 и CRS что и у тебя? окромя того что от HSI48 тактируется только USB. А вдруг?

Вай, отбой, у него в систем_инит  тактирование на HSI48 переводится...

30

dosikus
Если ты взялся за usb, то тебе лучше сразу книжку Жанетты - http://janaxelson.com/usbc.htm - имхо самое лучше что есть и там есть всё - от нуля до бесконечности, если не найдёшь, то выложу ненадолго
Ну и всем тоже советую эту книжку, конечно )

Про прерывания - условия прежние )
Да ты и сам всё увидишь если начнёшь практически писать скоростной обмен, дело не в накладных расходах на прерывания, а в синхронизации обмена и обработки

Отредактировано vt340 (2017-04-25 10:17:35)


Вы здесь » Микроконтроллеры » Архив » USB интерфейс в STM32F103