Bei der Arbeit mit USB HID auf STM32 ist die Überprüfung der USB-Belegung vor dem Aufruf von USBD_HID_SendReport() obligatorisch. Wenn ein Bericht gesendet wird, während der vorherige noch nicht verarbeitet ist, gehen die Daten verloren. Hier sind die wichtigsten Methoden zur Überprüfung:

1. Überprüfung des Rückgabewerts

c
uint8_t result = USBD_HID_SendReport(&hUsbDeviceFS, report_data, report_size);
if (result != USBD_OK) { // USB ist beschäftigt, später erneut versuchen // Man kann eine Verzögerung einbauen oder in der nächsten Schleifeniteration erneut versuchen }

2. Verwendung des EP-(Endpoint)-Status

c
// Überprüfen, ob der IN-Endpoint für die Übertragung bereit ist if ((hUsbDeviceFS.pClassData != NULL) && (USBD_LL_GetTxState(&hUsbDeviceFS, HID_EPIN_ADDR) == 0)) { USBD_HID_SendReport(&hUsbDeviceFS, report_data, report_size); }

3. Pufferung mit Warteschlange (empfohlen)
Für eine Tastatur ist es besser, eine Pufferung zu implementieren:

c
#define KEYBOARD_REPORT_QUEUE_SIZE 8
typedef struct { uint8_t modifier; uint8_t reserved; uint8_t keycode[6]; } keyboard_report_t; keyboard_report_t report_queue[KEYBOARD_REPORT_QUEUE_SIZE]; uint8_t queue_head = 0; uint8_t queue_tail = 0; uint8_t queue_count = 0; // Hinzufügen eines Berichts zur Warteschlange uint8_t keyboard_send_report(uint8_t modifier, uint8_t* keycodes) { if (queue_count >= KEYBOARD_REPORT_QUEUE_SIZE) { return USBD_BUSY; // Warteschlange ist voll } report_queue[queue_tail].modifier = modifier; memcpy(report_queue[queue_tail].keycode, keycodes, 6); queue_tail = (queue_tail + 1) % KEYBOARD_REPORT_QUEUE_SIZE; queue_count++; return keyboard_process_queue(); } // Verarbeitung der Warteschlange uint8_t keyboard_process_queue(void) { if (queue_count == 0) { return USBD_OK; } // Wenn USB bereit ist, Daten zu empfangen if (USBD_LL_GetTxState(&hUsbDeviceFS, HID_EPIN_ADDR) == 0) { keyboard_report_t* report = &report_queue[queue_head]; uint8_t result = USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*)report, sizeof(keyboard_report_t)); if (result == USBD_OK) { queue_head = (queue_head + 1) % KEYBOARD_REPORT_QUEUE_SIZE; queue_count--; } return result; } return USBD_BUSY; }

4. Callback bei Abschluss der Übertragung
Man kann einen Callback verwenden, der aufgerufen wird, wenn die Übertragung abgeschlossen ist:

c
// Im SOF-(Start Of Frame)-Handler oder in einem Timer
void USB_HID_Process(void) { keyboard_process_queue(); } // Oder in USBD_HID_TransmitCallback (falls in Ihrem HAL implementiert)

Praktisches Beispiel für eine Tastatur:

c
void send_keypress(uint8_t keycode) { uint8_t key_report[8] = {0, 0, keycode, 0, 0, 0, 0, 0}; // Mehrfache Versuche mit Timeout for(int i = 0; i < 10; i++) { if (USBD_HID_SendReport(&hUsbDeviceFS, key_report, 8) == USBD_OK) { break; } HAL_Delay(1); // Kurze Verzögerung } }

Wichtig:
Überprüfen Sie immer den Rückgabewert von USBD_HID_SendReport() und implementieren Sie einen Wiederholungs- oder Pufferungsmechanismus, um einen zuverlässigen Tastaturbetrieb sicherzustellen.

Umfrage
Schreiben Sie Ihre Meinung zu diesem Thema. Interessante Einsendungen werden auf der Website veröffentlicht.