Implement application specific behavior of a Communication Device Class (CDC) USB Device using the sub-class Abstract Control Model (ACM).
More...
Implement application specific behavior of a Communication Device Class (CDC) USB Device using the sub-class Abstract Control Model (ACM).
The CDC (ACM) class in the USB Component is used for data communication. You can typically use it in applications that previously used a serial COM or UART communication.
The USB Component allows multiple instances of the CDC class. This feature is used to create USB Composite Devices. Each CDC class instance has a separate files and interface functions:
The necessary descriptors are automatically generated by the USB Middleware Component. The page USB Descriptors provides more information on the topic.
The thread USBD_CDCn_Int_Thread handles Interrupt IN Endpoint whereas the USBD_CDCn_Bulk_Thread handles the Bulk IN and Bulk OUT Endpoints.
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (ACM) Device.
The following source code contains all the required callback functions and can be used to implement the application specific behavior of a USB CDC (ACM) Device that can be used as a USB <-> UART bridge.
#include <stdbool.h>
#include "rl_usb.h"
#include "Driver_USART.h"
#define UART_PORT n // UART Port number
#define UART_BUFFER_SIZE 512 // UART Buffer Size
#define _UART_Driver_(n) Driver_USART##n
#define UART_Driver_(n) _UART_Driver_(n)
extern ARM_DRIVER_USART UART_Driver_(UART_PORT);
#define ptrUART (&UART_Driver_(UART_PORT))
extern void CDCn_ACM_UART_to_USB_Thread (void const *arg) __attribute((noreturn));
static uint8_t uart_rx_buf[UART_BUFFER_SIZE];
static uint8_t uart_tx_buf[UART_BUFFER_SIZE];
static volatile int32_t uart_rx_cnt = 0;
static volatile int32_t usb_tx_cnt = 0;
static osThreadId cdc_acm_bridge_tid = 0U;
static void UART_Callback (uint32_t event) {
int32_t cnt;
if (event & ARM_USART_EVENT_SEND_COMPLETE) {
if (cnt > 0) {
ptrUART->Send(uart_tx_buf, (uint32_t)(cnt));
}
}
if (event & ARM_USART_EVENT_RECEIVE_COMPLETE) {
uart_rx_cnt += UART_BUFFER_SIZE;
ptrUART->Receive(uart_rx_buf, UART_BUFFER_SIZE);
}
}
void CDCn_ACM_UART_to_USB_Thread (void const *arg) {
int32_t cnt, cnt_to_wrap;
(void)(arg);
while (1) {
if (ptrUART->GetStatus().rx_busy != 0U) {
cnt = uart_rx_cnt;
cnt += ptrUART->GetRxCount();
cnt -= usb_tx_cnt;
if (cnt >= UART_BUFFER_SIZE) {
usb_tx_cnt += cnt;
cnt = 0U;
}
if (cnt > 0) {
cnt_to_wrap = (int32_t)(UART_BUFFER_SIZE - (usb_tx_cnt & (UART_BUFFER_SIZE - 1)));
if (cnt > cnt_to_wrap) {
cnt = cnt_to_wrap;
}
if (cnt > 0) {
usb_tx_cnt += cnt;
}
}
}
osDelay(10U);
}
}
extern const osThreadDef_t os_thread_def_CDCn_ACM_UART_to_USB_Thread;
osThreadDef (CDCn_ACM_UART_to_USB_Thread, osPriorityNormal, 1U, 0U);
int32_t cnt;
(void)(len);
if (ptrUART->GetStatus().tx_busy == 0U) {
if (cnt > 0) {
ptrUART->Send(uart_tx_buf, (uint32_t)(cnt));
}
}
}
ptrUART->Initialize (UART_Callback);
ptrUART->PowerControl (ARM_POWER_FULL);
cdc_acm_bridge_tid = osThreadCreate (osThread (CDCn_ACM_UART_to_USB_Thread), NULL);
}
if (osThreadTerminate (cdc_acm_bridge_tid) == osOK) {
cdc_acm_bridge_tid = 0U;
}
ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
ptrUART->PowerControl (ARM_POWER_OFF);
ptrUART->Uninitialize ();
}
ptrUART->Control (ARM_USART_ABORT_SEND, 0U);
ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
}
uint32_t data_bits = 0U, parity = 0U, stop_bits = 0U;
int32_t status;
ptrUART->Control (ARM_USART_ABORT_SEND, 0U);
ptrUART->Control (ARM_USART_ABORT_RECEIVE, 0U);
ptrUART->Control (ARM_USART_CONTROL_TX, 0U);
ptrUART->Control (ARM_USART_CONTROL_RX, 0U);
case 0:
stop_bits = ARM_USART_STOP_BITS_1;
break;
case 1:
stop_bits = ARM_USART_STOP_BITS_1_5;
break;
case 2:
stop_bits = ARM_USART_STOP_BITS_2;
}
case 0:
parity = ARM_USART_PARITY_NONE;
break;
case 1:
parity = ARM_USART_PARITY_ODD;
break;
case 2:
parity = ARM_USART_PARITY_EVEN;
break;
default:
return false;
}
case 5:
data_bits = ARM_USART_DATA_BITS_5;
break;
case 6:
data_bits = ARM_USART_DATA_BITS_6;
break;
case 7:
data_bits = ARM_USART_DATA_BITS_7;
break;
case 8:
data_bits = ARM_USART_DATA_BITS_8;
break;
default:
return false;
}
status = ptrUART->Control(ARM_USART_MODE_ASYNCHRONOUS |
data_bits |
parity |
stop_bits |
ARM_USART_FLOW_CONTROL_NONE ,
if (status != ARM_DRIVER_OK) {
return false;
}
cdc_acm_line_coding = *line_coding;
uart_rx_cnt = 0;
usb_tx_cnt = 0;
ptrUART->Control (ARM_USART_CONTROL_TX, 1U);
ptrUART->Control (ARM_USART_CONTROL_RX, 1U);
ptrUART->Receive (uart_rx_buf, UART_BUFFER_SIZE);
return true;
}
*line_coding = cdc_acm_line_coding;
return true;
}
(void)(state);
return true;
}