|
1. Conexión entre los niveles superior e inferior En la sección anterior, hablamos sobre el uso de ADCs y muestreamos el sensor de temperatura integrado en el chip. En proyectos reales, el número de sensores suele ser grande y se debe procesar una gran cantidad de datos de conversión. Mover estos datos pondrá mucha presión en la CPU. Para liberar la CPU y darle energía para hacer otras cosas, el DMA (Acceso Directo a la Memoria) puede ser muy útil~ La siguiente introducción es un extracto del Tutorial de Práctica de Tecnología Zigbee: DMA es una abreviatura de acceso directo a la memoria, que es "acceso directo a memoria". Se trata de un modo de transmisión de datos de alta velocidad en el que unidades periféricas como transceptores ADC/UART/RF y memoria pueden intercambiar datos directamente bajo el control del "controlador DMA" sin poca intervención de la CPU. Además de hacer un poco de procesamiento al principio y al final de la transferencia de datos, la CPU puede realizar otros trabajos durante la transferencia. De este modo, la CPU y estas interacciones de datos trabajan en paralelo la mayor parte del tiempo. Como resultado, la eficiencia global del sistema puede mejorarse considerablemente.
Como puedes ver en la introducción, el DMA puede usarse en muchos escenarios. Este experimento implica únicamente la transmisión de DMA más sencilla y tiene como objetivo demostrar el uso general de la DMA. En cuanto a la aplicación de la DMA en otros escenarios, se implementará en experimentos integrales en el futuro. 2. Experimento de transmisión DMA(1) Introducción al experimentoPersonajes del arraysourceStringEl contenido se transfiere al array de caracteres mediante DMAdestString, el resultado de la conversión se muestra en el PC a través del puerto serial. (2) Diagrama de flujo del programa
(3) Código fuente experimental y análisis/*
Descripción experimental: El contenido de la sourceString del array de caracteres se transfiere al array de caracteres destString a través de DMA, y el resultado de conversión se muestra en el PC a través del puerto serial.
*/
#include
#define lideró P1_0
#define P1_1 LED2
#define led3 P1_2
#define led4 P1_3
/*用于配置DMA的结构体
-------------------------------------------------------*/
#pragma campos de bits=invertido
typedef struct
{
sin firmar charSRCADDRH; //源地址高8位
sin firmar charSRCADDRL; //源地址低8位
sin firmar charDESTADDRH; //目的地址高8位
sin firmar charDESTADDRL; //目的地址低8位
sin firmar charVLEN:3; //长度域模式选择
sin firmar charLENH:5; //传输长度高字节
sin firmar charLENL:8; //传输长度低字节
sin firmar charTAMAÑO DE PALABRA :1; //字节(byte)或字(word)传输
sin firmar charTMODE:2; //传输模式选择
sin firmar charTRIG:5; //触发事件选择
sin firmar charSRCINC :2; //源地址增量:-1/0/1/2
sin firmar charDESTINC:2; //目的地址增量:-1/0/1/2
sin firmar charIRQMASK :1; //中断屏蔽
sin firmar charM8:1; //7或8bit传输长度,仅在字节传输模式下适用
sin firmar charPRIORIDAD:2; //优先级 }DMA_CFG; #pragma campos de bits=predeterminado
/*系统时钟初始化
-------------------------------------------------------*/
Vacíoxtal_init(Vacío)
{ SUEÑO &= ~0x04; //都上电
mientras(! (SUEÑO &0x40)); //晶体振荡器开启且稳定 CLKCON &= ~0x47; Elige un oscilador de cristal de 32MHz SUEÑO |=0x04;
}
/*LED初始化
-------------------------------------------------------*/
Vacíoled_init(Vacío)
{ P1SEL =0x00; P1 es el puerto normal de E/S P1DIR |=0x0F; P1.0 P1.1 P1.2 P1.3 salida
liderado1 =1; //关闭所有LED Liderado2 =1; liderado3 =1; Liderado4 =1;
}
/*UART0通信初始化
-------------------------------------------------------*/
VacíoUart0Init(sin firmar charStopBits,sin firmar charParidad)
{ P0SEL |= 0x0C; //初始化UART0端口,设置P0.2与P0.3为外部设备IO口 PERCFG&= ~0x01; Selecciona UART0 como primera posición opcional, es decir, RXD a P0.2 y TXD a P0.3
U0CSR =0xC0; Configura en modo UART y activa el aceptor
U0GCR =11; U0BAUD =216; //设置UART0波特率为115200bps
U0UCR |= StopBits| Paridad; //设置停止位与奇偶校验
}
/*UART0发送数据
-------------------------------------------------------*/
Vacío Uart0Send(sin firmar chardatos)
{
mientras(U0CSR&0x01); //等待UART空闲时发送数据 U0DBUF = datos;
}
/*UART0发送字符串
-------------------------------------------------------*/
VacíoUart0SendString(sin firmar char*s)
{
mientras(*s !=0) //依次发送字符串s中的每个字符 Uart0Send(*s++);
}
/*主函数
-------------------------------------------------------*/
Vacíomain(Vacío)
{ DMA_CFG dmaConfig; //定义配置结构体
sin firmar charsourceString[]="¡Soy la FuenteString!"; //源字符串
sin firmar chardestString[Tamañode(fuenteString)] ="¡Soy el DestString!"; //目的字符串
charYo;
charerror=0;
xtal_init(); //系统时钟初始化 led_init(); Uart0Init(0x00,0x00); //UART初始化
Uart0SendString(sourceString); //传输前的原字符数组 Uart0SendString(destString); //传输前的目的字符数组
//配置DMA结构体 dmaConfig.SRCADDRH=(sin firmar char)((sin firmar int)y fuente de cadena >>8); //源地址 dmaConfig.SRCADDRL=(sin firmar char)((sin firmar int)y fuenteString);
dmaConfig.DESTADDRH=(sin firmar char)((sin firmar int)&destString >>8); //目的地址 dmaConfig.DESTADDRL=(sin firmar char)((sin firmar int)&destString);
dmaConfig.VLEN=0x00; //选择LEN作为传送长度
dmaConfig.LENH=(sin firmar char)((sin firmar int)Tamañode(fuenteString) >>8); //传输长度 dmaConfig.LENL=(sin firmar char)((sin firmar int)Tamañode(sourceString));
dmaConfig.WORDSIZE=0x00; //选择字节(byte)传送
dmaConfig.TMODE=0x01; //选择块传送(block)模式
dmaConfig.TRIG=0; Sin disparador (puede entenderse como disparo manual)
dmaConfig.SRCINC=0x01; //源地址增量为1
dmaConfig.DESTINC=0x01; //目的地址增量为1
dmaConfig.IRQMASK=0; //DMA中断屏蔽
dmaConfig.M8=0x00; //选择8位长的字节来传送数据
dmaConfig.PRIORITY=0x02; //传输优先级为高
DMA0CFGH=(sin firmar char)((sin firmar int)&dmaConfig >>8); //将配置结构体的首地址赋予相关SFR DMA0CFGL=(sin firmar char)((sin firmar int)&dmaConfig);
DMAARM=0x01; //启用配置
DMAIRQ=0x00; //清中断标志 DMAREQ=0x01; //启动DMA传输
mientras(! (DMAIRQ&0x01)); //等待传输结束
para(i=0; Yo <Tamañode(fuenteString); i++) //校验传输的正确性 {
si(sourceString!=destString) error++; }
si(error==0) //将结果通过串口传输到PC { Uart0SendString("¡Correcto!"); Uart0SendString(destString); //传输后的目的字符数组 }
si no, Uart0SendString("¡Error!");
mientras(1);
}
El proceso básico para usar DMA es:Configurar DMA → Habilitar configuración → Empieza la transferencia DMA → espera a que termine la transferencia DMA.Los siguientes son, respectivamente: (1) Configurar DMA: En primer lugar, la DMA debe configurarse, pero la configuración de la DMA es especial: en lugar de asignar directamente valores a algunos SFR, define una estructura externamente, le asigna valores y luego asigna los 8 bits altos de la primera dirección de esta estructuraDMA0CFGH, dándole un número inferior de 8 dígitosDMA0CFGL。 (Para instrucciones detalladas en la estructura de configuración, consulte el manual chino CC2430) Consejos CC2430Hay dos puntos que aclarar sobre la definición de estructuras de configuración en el código fuente anterior: (1) Dominio de bits Al definir esta estructura, se utilizan muchos dos puntos (:), seguidos de un número, que se llama "campo de bits": Dominio de bits significa que la información no necesita ocupar un byte completo cuando se almacena, sino que solo ocupa unos pocos o un bit binario. Por ejemplo, al almacenar una magnitud de conmutación, solo hay dos estados, 0 y 1, y puedes usar un bit binario. Para ahorrar espacio de almacenamiento y facilitar el procesamiento, C proporciona una estructura de datos llamada "campo de bits" o "campo de bits". El llamado "campo de bits" divide los binarios de un byte en varias regiones diferentes y describe el número de bits en cada región. Cada dominio tiene un nombre de dominio, lo que permite operaciones por nombre de dominio en el programa. Esto permite representar varios objetos diferentes en un campo de bits binario de bytes. (2) Funciones comunes abstractas Los lectores atentos descubrirán que asignar un valor a una estructura suele implicar asignar un valor de tipo int sin signo de 16 bits a dos valores de tipo de char sin signo de 8 bits, de la siguiente manera: dmaConfig.SRCADDRH=(sin firmar char)((sin firmar int)y fuente de cadena >>8); //源地址 dmaConfig.SRCADDRL=(sin firmar char)((sin firmar int)y fuenteString);
Para este tipo de función frecuente, bien podríamos abstraerla como función general, de la siguiente manera: #define SET_WORD(destH,destL,word)
hacer{ destH=(sin firmar char)((sin firmar int)palabra >>8); destL=(sin firmar char)((sin firmar int)palabra); }mientras(0)
En el futuro, siempre que necesites realizar una operación de división similar, puedes llamarla directamente, de la siguiente manera: SET_WORD(dmaConfig.SRCADDRH, dmaConfig.SRCADDRL, & sourceString);
(2) Habilitar la configuración: Primero, la primera dirección de la estructura&dmaConfigLos 8 bits alto/bajo se asignan respectivamente a SFRDMA0CFGHyDMA0CFGL(donde 0 representa la configuración del canal 0, CC2430 contiene 5 canales DMA, y aquí se usa el canal 0). SíDMAARM.0Asigna un valor de 1 para habilitar la configuración del canal 0 y que el canal 0 esté en modo de trabajo. (3) Habilitar la transmisión DMA:DerechaDMAREQ.0Asigna un valor de 1 para iniciar la transmisión DMA del canal 0. (4) Esperar a que se transmita el DMA:Tras la transmisión del DMA del canal 0, se activará la interrupción y se activará la bandera de interrupción del canal 0DMAIRQ.0se pondrá automáticamente en 1. Luego se compara cada carácter de las dos cadenas y el resultado de verificación se envía al PC. (4) Resultados experimentalesPrimero, abre la herramienta de depuración de puertos seriales y luego comienza la depuración de CC2430, y aparecerá la siguiente pantalla:
EncontrarásdestStringEl contenido ha sido completamente reveladosourceStringlleno. Hecho~ 3. ConclusiónEsta sección introduce el uso de la DMA, aunque es muy sencilla, pero creo que has entendido el uso básico de la DMA, y también puedes analizarla con calma cuando te enfrentes a sus complejos escenarios de uso en el futuro. Por muy bueno que sea un escritorio, se congelará y, de forma similar, un sistema embebido inevitablemente se estancará. En la siguiente sección, presentaremos un método muy eficaz de reinicio sistemático: los watchdogs.
|