Emulando un puerto RS-232 con USB.
Como sabemos el puerto USB puede funcionar de distintas formas dependiendo del tipo de dispositivo que conectemos en el. (Cámaras de fotos, teclados, Memorias, etc) .
Cada uno de estos dispositivos están “clasificados” dentro de la arquitectura del USB.
Universal Serial Bus Communication Device Class (USB CDC) es una de esas clases que emula un puerto serial clásico (RS-232) y para poder implementarlo en nuestro Cortex M4 de STM vamos a necesitar los correspondientes drivers provistos por STM.
Como todo programa en C el punto de entrada a nuestra aplicación es main.c y configura los LED´s de la placa entrenadora para que se comporten de forma tal que nos pueda dar indicios de su estado operativo por ejemplo si todo ha sido correcto en la ejecución del código tendremos un LED destellando en la placa, también configura el USB de nuestro micro en modo CDC y cuando la computadora enumere nuestro dispositivo otro LED indicará que está listo para trabajar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*************************************************************
* Nombre : VCP.c
* Descripción : Demo para el Com Virtual (USB_CDC)
* Target : STM32F407VG
* ToolChain : MDK-ARM
* www.firtec.com.ar
***************************************************************/
#include "stm32f4xx.h"
#include "usbd_cdc_core.h"
#include "usbd_cdc_vcp.h"
#include "usbd_usr.h"
#include "usbd_desc.h"
__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END ;
void Delay(__IO uint32_t nTick);
int main(void)
{
uint32_t i = 0;
// Configura los perifericos de la placa entrenadora
STM32F4_Discovery_LEDInit(LED3);
STM32F4_Discovery_LEDInit(LED4);
STM32F4_Discovery_LEDInit(LED5);
STM32F4_Discovery_LEDInit(LED6);
STM32F4_Discovery_PBInit(BUTTON_USER, BUTTON_MODE_EXTI);
STM32F4_Discovery_LEDOn(LED3); // LED naranja encendido
// Configura el puerto USB en modo CDC
USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,
&USR_desc,&USBD_CDC_cb,&USR_cb);
while (1)
{
if (i++ == 0x100000)
{ // Enciende/Apaga LED verde
STM32F4_Discovery_LEDToggle(LED4);
i = 0;
}
}
}
El objetivo de este trabajo es que nuestro micro nos conteste como un eco lo que se escribe en la terminal también si oprimimos el botón de usuario se dispara una interrupción que envía un mensaje con la palabara Firtec.
La aplicación será controlada por el archivo usbd_cdc_vcp.c que contiene todas las funciones operativas para el envío de datos por el puerto virtual.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*************************************************************
* Nombre : usbd_cdc_vcp.c
* Descripción : Capa de para acceder al medio USB_CDC
* Target : STM32F407VG
* ToolChain : MDK-ARM
* www.firtec.com.ar
***************************************************************/
#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
#pragma data_alignment = 4
#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */
#include "usbd_cdc_vcp.h"
#include "stm32f4_discovery.h"
LINE_CODING linecoding =
{
115200, /* baud rate*/
0x01, /* stop bits-1*/
0x00, /* sin paridad*/
0x08 /* cantidad de bits 8*/
};
USART_InitTypeDef USART_InitStructure;
/* Variables importadas del nucleo CDC */
extern uint8_t APP_Rx_Buffer []; /* En este Buffer recibe los datos desde el EndPoint. */
extern uint32_t APP_Rx_ptr_in; /* Este puntero se utiliza para recorrer APP_Rx_Buffer */
/* Prototipos de Funciones */
void DISCOVERY_COM_IRQHandler(void);
static uint16_t VCP_Init (void);
static uint16_t VCP_DeInit (void);
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len);
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len);
CDC_IF_Prop_TypeDef VCP_fops =
{
VCP_Init,VCP_DeInit,VCP_Ctrl,VCP_DataTx,VCP_DataRx
};
//----------------------------------------------------
// Estas dos funciones inicializan los medios de
// comunicaciónes de STM32 (Deben estar en el código)
static uint16_t VCP_Init(void)
{
return USBD_OK;
}
//----------------------------------------------------
static uint16_t VCP_DeInit(void)
{
return USBD_OK;
}
//*****************************************************************
// Esta función administra las solicitudes de clase CDC del USB
// Procesa los comandos y retorna OK si todo a salido bien.
//*****************************************************************
static uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len)
{
switch (Cmd)
{
case SEND_ENCAPSULATED_COMMAND:
/* No es necesario para este driver */
break;
case GET_ENCAPSULATED_RESPONSE:
/* No es necesario para este driver */
break;
case SET_COMM_FEATURE:
/* No es necesario para este driver */
break;
case GET_COMM_FEATURE:
/* No es necesario para este driver */
break;
case CLEAR_COMM_FEATURE:
/* No es necesario para este driver */
break;
case GET_LINE_CODING:
Buf[0] = (uint8_t) (linecoding.bitrate);
Buf[1] = (uint8_t) (linecoding.bitrate >> 8);
Buf[2] = (uint8_t) (linecoding.bitrate >> 16);
Buf[3] = (uint8_t) (linecoding.bitrate >> 24);
Buf[4] = linecoding.format;
Buf[5] = linecoding.paritytype;
Buf[6] = linecoding.datatype;
break;
case SET_CONTROL_LINE_STATE:
/* No es necesario para este driver */
break;
case SEND_BREAK:
/* No es necesario para este driver */
break;
default:
break;
}
return USBD_OK;
}
/***************************************************************************
* Función VCP_DataTx
* Esta funcion transmite los datos por el USB_CDC
* Buf: Buffer de datos que seran enviados
* Len: Numero de datos a envianr (en bytes)
* Resultado de la operacion, SBD_OK si falla la operacion VCP_FAIL
***************************************************************************/
static uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{
if (linecoding.datatype == 7)
{
APP_Rx_Buffer[APP_Rx_ptr_in] = (uint8_t) Len & 0x7F;
}
else if (linecoding.datatype == 8)
{
APP_Rx_Buffer[APP_Rx_ptr_in] = (uint8_t) Len ;
}
APP_Rx_ptr_in++;
if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
{
APP_Rx_ptr_in = 0;
}
return USBD_OK;
}
//*********************************************************************************
// Función: VCP_DataRx recibe los datos por el USB_CDC.
// Parametro Buf: Búfer de datos recibidos
// Parametro Len: Número de datos (en bytes)
// Retorna: Resultado de la operación, USBD_OK si todo OK, VCP_FAIL si error
//**********************************************************************************
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
VCP_DataTx (0,* Buf);
return USBD_OK;
}
void DISCOVERY_EXTI_IRQHandler(void) // ISR de la interrupción del botón de usuario.
{
/* Transmite Firtec cuando se oprime el boton de usurario */
VCP_DataTx (0, (uint32_t) 'F');
VCP_DataTx (0, (uint32_t) 'i');
VCP_DataTx (0, (uint32_t) 'r');
VCP_DataTx (0, (uint32_t) 't');
VCP_DataTx (0, (uint32_t) 'e');
VCP_DataTx (0, (uint32_t) 'c');
}
El proyecto completo para descargar.