先说下CC3200存在2个16*8的fifos, 分别用于发送和接收
当fifos被disable时,将会作为一个1字节深度的保持寄存器,
所以无论fifos是开是关,发送和接收都绕不开fifos
DMA
由于发送和接收都绕不过fifos,所以DMA也绕不开FIFOS.
c
MAP_UARTFIFOLevelSet(UARTA0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
上述代码的意思就是,设定FIFO,UART_FIFO_TX4_8当达到1/2 * 16
字节时才会触发DMA传输,小于8字节时不触发DMA传输,所以这个时候要用到UART外设自带的接收超时中断,类似于STM32的idle中断.
需要注意的是,触发DMA后,仅仅是把数据从uart外设寄存器搬运到了用户指定的ram中
DMA中也有一个阈值参数,叫做仲裁大小,他决定了DMA每次最多连续搬运字节数.仲裁大小别称ARB, ARB<=FIFO阈值
所以在传输1024字节数据时,ARB设定为32,DMA就会以32字节为单位进行数据搬运
此外,在手册里有如下说明.
The arbitration size can also be thought of as a burst size, as it is the maximum number of items that are transferred at any one time in a burst. Here, the term arbitration refers to determination of μDMA channel priority, not arbitration for the bus. When the μDMA controller arbitrates for the bus, the processor always takes priority. Furthermore, the μDMA controller is held off whenever the processor must perform a bus transaction on the same bus, even in the middle of a burst transfer.
即对于总线竞争时,CPU > DMA, 上面的ARB大小的仲裁仅为DMA多通道之间优先级的仲裁,每搬运ARB SIZE
大小的数据后检查一次DMA通道的优先级.
DMA
串口超时中断
UART的超时中断触发条件
这个和32的IDLE功能类似,但是触发机制完全不同.
32是超过一定时间没接收数据就触发,但是触发后除非再次接收到数据否则不会再触发
这个触发机制看原文描述
The receive timeout interrupt is asserted when the receive FIFO is not empty
and no further data is received over a 32-bit period when the HSE bit is clear, or over a 64-bit period when the HSE bit is set
即满足FIFO不为空,且在32周期或者64周期没接收(根据HSE位区分)FIFO数据。简单理解只要FIFO内存在数据超过一定时间就会触发,如果你一直不接受数据,则一直触发哪怕清除中断位后还是会不停触发.4
这个和FIFO阈值及ARB强相关。
FIFO阈值决定了FIFO达到多少数据触发DMA搬运,ARB决定了DMA单次搬运的数据大小.
举两个例子
FIFO = 1/8触发,ARB = 2 则仅在FIFO剩余1个字节时触发RT,为什么使用FIFO仅剩1个字节的字眼,因为当你单次发送奇数时即会触发该中断.
FIFO = 1/4触发,ARB = 2 ,FIFO字节大于等于4触发,每次搬运2个,即无论发送多少个都会触发RT中断
所以设定fifo要注意,如果fifo大小和URB大小一致,会导致发送数据为URB大小时,数据被完全搬运到了缓存,导致不触发RT中断.
DMARX_INT
这个也是串口的中断,体现在代码中叫做UART_INT_DMARX
这个中断在手册中描述如下
If DMA is enabled, then the μDMA controller triggers an interrupt when a transfer is complete. The
interrupt occurs on the UART interrupt vector. Therefore, if interrupts are used for UART operation and
DMA is enabled, the UART interrupt handler must be designed to handle the μDMA completion interrupt.
经过实际测试,在基础模式下,这个在仅在dma传输完成设定大小的数据后触发.
CC3200的DMA中断和STM32不太一样
参考文档给出说明如下所示
Few μDMA channels are dedicated to software-initiated transfers. This channel also has a dedicated
interrupt to signal completion of a μDMA transfer. A transfer is initiated by software by first configuring and
enabling the transfer, and then issuing a software request using the DMA Channel Software Request
(DMASWREQ) register. For software-based transfers, use the auto transfer mode.
When a μDMA transfer is complete, a dma_done signal is sent to the peripheral that initiated the μDMAevent. Interrupts can be enabled within the peripheral to trigger on μDMA transfer completion. If the
transfer uses the software μDMA channel, then the completion interrupt occurs on the dedicated software
μDMA interrupt vector.
可以看到DMA的中断仅针对软件dma有用,也就是说仅针对m to m
有用,针对外设相关DMA,所有中断都发送到外设自己的中断内处理.
此外,本来想使用ping-pong模式,但是调试了1天在最开始接受的几组数据中始终会有丢包现象,不知道哪地方的设置出问题了,所以最后选用了基础模式.
示例1 测试rx及dmarx的功能
本demo测试基本dma传输.
主要测试超时中断及uart_dmarx
c
// Driverlib includes
#include "hw_types.h"
#include "hw_uart.h"
#include "hw_ints.h"
#include "hw_memmap.h"
#include "hw_common_reg.h"
#include "interrupt.h"
#include "hw_apps_rcm.h"
#include "prcm.h"
#include "rom.h"
#include "prcm.h"
#include "rom_map.h"
#include "gpio.h"
#include "utils.h"
#include "uart.h"
#include "udma.h"
// user includes
#include "pin_mux_config.h"
#include "uart_if.h"
#include "systick_if.h"
#include "wifi.h"
#include "wlan.h"
#include "stdio.h"
#include "udma_if.h"
//*****************************************************************************
// GLOBAL VARIABLES -- Start
//*****************************************************************************
#if defined(ccs)
extern void (* const g_pfnVectors[])(void);
#endif
#if defined(ewarm)
extern uVectorEntry __vector_table;
#endif
//*****************************************************************************
// GLOBAL VARIABLES -- End
//*****************************************************************************
//*****************************************************************************
// LOCAL FUNCTION PROTOTYPES
//*****************************************************************************
void LEDBlinkyRoutine();
static void BoardInit(void);
//*****************************************************************************
// LOCAL FUNCTION DEFINITIONS
//*****************************************************************************
//*****************************************************************************
static void BoardInit(void)
{
/* In case of TI-RTOS vector table is initialize by OS itself */
#ifndef USE_TIRTOS
//
// Set vector table base
//
#if defined(ccs)
MAP_IntVTableBaseSet((unsigned long)&g_pfnVectors[0]);
#endif
#if defined(ewarm)
MAP_IntVTableBaseSet((unsigned long)&__vector_table);
#endif
#endif
//
// Enable Processor
//
MAP_IntMasterEnable();
MAP_IntEnable(FAULT_SYSTICK);
PRCMCC3200MCUInit();
}
extern void tcp_rate_test_example(wifi_t wifi);
extern void cw_burst_forever();
#define UART_TXBUF_SIZE (256)
#define UART_RXBUF_SIZE (256)
static unsigned char g_ucTxBuf[UART_TXBUF_SIZE];
static unsigned char g_ucRxBufA[UART_RXBUF_SIZE];
static unsigned char g_ucRxBufB[UART_RXBUF_SIZE];
void
UART0IntHandler(void)
{
static long recv_cnt = 0;
unsigned long ulStatus;
unsigned long ulMode;
long cnt = 0;
//
// Read the interrupt status of the UART.
//
ulStatus = MAP_UARTIntStatus(UARTA0_BASE, 1);
//
// Clear any pending status, even though there should be none since no UART
// interrupts were enabled.
//
MAP_UARTIntClear(UARTA0_BASE, ulStatus);
ulMode = MAP_uDMAChannelModeGet(UDMA_CH8_UARTA0_RX);
if(ulMode == UDMA_MODE_STOP)
{
Report("dma restart\r\n");
//
// Set up the next transfer for the "A" buffer, using the primary
// control structure. When the ongoing receive into the "B" buffer is
// done, the uDMA controller will switch back to this one.
//
UDMASetupTransfer(UDMA_CH8_UARTA0_RX, UDMA_MODE_BASIC,
8,UDMA_SIZE_8, UDMA_ARB_4,
(void *)(UARTA0_BASE + UART_O_DR), UDMA_SRC_INC_NONE,
g_ucRxBufA, UDMA_DST_INC_8);
// return;
}
if(ulStatus & UART_INT_RT)
{
while(MAP_UARTCharsAvail(UARTA0_BASE))
{
uint8_t data = MAP_UARTCharGetNonBlocking(UARTA0_BASE);
cnt ++;
Report("cnt %d:0x%02x\r\n", cnt, data);
if (cnt > 5)
break;
}
}
else if (ulStatus & UART_INT_DMARX)
{
Report("rx int\r\n");
}
}
void
InitUART0Transfer(void)
{
unsigned int uIdx;
//
// Fill the TX buffer with a simple data pattern.
//
for(uIdx = 0; uIdx < UART_TXBUF_SIZE; uIdx++)
{
g_ucTxBuf[uIdx] = 65;
}
MAP_PRCMPeripheralReset(PRCM_UARTA0);
MAP_PRCMPeripheralClkEnable(PRCM_UARTA0,PRCM_RUN_MODE_CLK);
MAP_UARTConfigSetExpClk(CONSOLE,SYSCLK, UART_BAUD_RATE,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));
MAP_uDMAChannelAssign(UDMA_CH8_UARTA0_RX);
MAP_uDMAChannelAssign(UDMA_CH9_UARTA0_TX);
MAP_UARTIntRegister(UARTA0_BASE,UART0IntHandler);
//
// Set both the TX and RX trigger thresholds to 4. This will be used by
// the uDMA controller to signal when more data should be transferred. The
// uDMA TX and RX channels will be configured so that it can transfer 4
// bytes in a burst when the UART is ready to transfer more data.
//
MAP_UARTFIFOLevelSet(UARTA0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX2_8);
//
// Enable the UART for operation, and enable the uDMA interface for both TX
// and RX channels.
//
MAP_UARTEnable(UARTA0_BASE);
//
// Enable the UART peripheral interrupts. uDMA controller will cause an
// interrupt on the UART interrupt signal when a uDMA transfer is complete.
//
MAP_UARTIntEnable(UARTA0_BASE,UART_INT_DMARX);
MAP_UARTIntEnable(UARTA0_BASE,UART_INT_RT);
UDMASetupTransfer(UDMA_CH8_UARTA0_RX,
UDMA_MODE_BASIC,
// sizeof(g_ucRxBufA),
8,
UDMA_SIZE_8,
UDMA_ARB_4,
(void *)(UARTA0_BASE+UART_O_DR),
UDMA_SRC_INC_NONE,
(void *)g_ucRxBufA,
UDMA_DST_INC_8);
MAP_UARTDMAEnable(UARTA0_BASE,UART_DMA_RX);
}
void main()
{
BoardInit();
PinMuxConfig();
SysTickInit();
InitTerm();
UDMAInit();
// wifi_t wifi = wifi_create();
#define GPIOSetLevel(gpio_port, gpio_pin, value) GPIOPinWrite(gpio_port, gpio_pin, value != 0 ? gpio_pin : 0)
// wifi_connect(wifi, "ultra-wifi", "ultra@2021", SL_SEC_TYPE_WPA_WPA2);
// wifi_connect(wifi, "360WiFi-864040", "87654321", SL_SEC_TYPE_WPA_WPA2);
// wifi_connect(wifi, "quanjing_test", "Iot@tytc00!", SL_SEC_TYPE_WPA_WPA2);
InitUART0Transfer();
while (1)
{
// cw_burst_forever();
// tcp_rate_test_example(wifi);
// GPIOSetLevel(GPIOA1_BASE, GPIO_PIN_1, !GPIOPinRead(GPIOA1_BASE,GPIO_PIN_1));
// UTUtilsDelay(10000 * 1000);
}
}
示例2 测试basic dma2M全速接收串口数据
c
// Driverlib includes
#include "hw_types.h"
#include "hw_memmap.h"
#include "rom_map.h"
#include "prcm.h"
#include "hw_uart.h"
#
#include "uart.h"
#include "udma.h"
// sdk user includes
#include "uart_if.h"
#include "udma_if.h"
#include "systick_if.h"
// user includes
#include "uart_itf.h"
#include "RingBuf.h"
#undef UART_BAUD_RATE
// #define UART_BAUD_RATE 115200
#define UART_BAUD_RATE 2000000
#define SYSCLK 80000000
#define UART_TXBUF_SIZE (1024)
#define UART_RXBUF_SIZE (1024)
static unsigned char g_ucRxBufA[UART_RXBUF_SIZE];
static rb_t rb;
static unsigned char rx_data[UART_RXBUF_SIZE * 100];
static uint64_t last_time = 0;
static void UARTIntHandler(void)
{
unsigned long ulStatus;
unsigned long ulMode;
ulStatus = MAP_UARTIntStatus(UART_ITF_BASE, 1);
MAP_UARTIntClear(UART_ITF_BASE, ulStatus);
Report("ulStatus:%x\r\n", ulStatus);
if (ulStatus & UART_INT_DMARX)
{
ulMode = MAP_uDMAChannelModeGet(UART_ITF_RX_DMA_CH);
if(ulMode == UDMA_MODE_STOP)
{
rbWrite(&rb, g_ucRxBufA, UART_RXBUF_SIZE);
UDMASetupTransfer(UART_ITF_RX_DMA_CH,
UDMA_MODE_BASIC,
sizeof(g_ucRxBufA),
// 8,
UDMA_SIZE_8,
UDMA_ARB_8,
(void *)(UART_ITF_BASE+UART_O_DR),
UDMA_SRC_INC_NONE,
(void *)g_ucRxBufA,
UDMA_DST_INC_8);
}
}
else if(ulStatus & UART_INT_RT)
{
UDMAStopTransfer(UART_ITF_RX_DMA_CH);
uint32_t received = UART_RXBUF_SIZE - MAP_uDMAChannelSizeGet(UART_ITF_RX_DMA_CH);
if (received != 0 && received <= UART_RXBUF_SIZE)
{
rbWrite(&rb, g_ucRxBufA, received);
UDMASetupTransfer(UART_ITF_RX_DMA_CH,
UDMA_MODE_BASIC,
sizeof(g_ucRxBufA),
// 8,
UDMA_SIZE_8,
UDMA_ARB_8,
(void *)(UART_ITF_BASE+UART_O_DR),
UDMA_SRC_INC_NONE,
(void *)g_ucRxBufA,
UDMA_DST_INC_8);
}
while(MAP_UARTCharsAvail(UART_ITF_BASE))
{
uint8_t data = MAP_UARTCharGetNonBlocking(UART_ITF_BASE);
rbWrite(&rb, &data, 1);
}
}
}
void uart_itf_init(void)
{
UDMAInit();
MAP_PRCMPeripheralReset(UART_ITF_PRCM);
MAP_PRCMPeripheralClkEnable(UART_ITF_PRCM,PRCM_RUN_MODE_CLK);
MAP_UARTConfigSetExpClk(UART_ITF_BASE,SYSCLK, UART_BAUD_RATE,
(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE));
MAP_uDMAChannelAssign(UART_ITF_RX_DMA_CH);
// MAP_uDMAChannelAssign(UART_ITF_TX_DMA_CH);
MAP_UARTIntRegister(UART_ITF_BASE,UARTIntHandler);
MAP_UARTFIFOLevelSet(UART_ITF_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
MAP_UARTEnable(UART_ITF_BASE);
MAP_UARTIntEnable(UART_ITF_BASE,UART_INT_DMARX | UART_INT_RT);
UDMASetupTransfer(UART_ITF_RX_DMA_CH,
UDMA_MODE_BASIC,
sizeof(g_ucRxBufA),
// 8,
UDMA_SIZE_8,
UDMA_ARB_8,
(void *)(UART_ITF_BASE+UART_O_DR),
UDMA_SRC_INC_NONE,
(void *)g_ucRxBufA,
UDMA_DST_INC_8);
MAP_UARTDMAEnable(UART_ITF_BASE,UART_DMA_RX);
rbInit(&rb, rx_data, sizeof(rx_data));
}
int32_t uart_itf_get_can_read(void)
{
return rbCanRead(&rb);
}
int32_t uart_itf_recv(void *data, uint32_t count)
{
return rbRead(&rb, data, count);
}
int32_t uart_itf_send(void *data, uint32_t count)
{
for (int i = 0; i < count; i++)
{
while (UARTBusy(UART_ITF_BASE));
UARTCharPut(UART_ITF_BASE, ((uint8_t *)data)[i]);
}
return count;
}
#define SEND_CHUNK_SIZE 1460
void test_uart_recv_basic_process()
{
uart_itf_init();
uint64_t total_bytes = 0;
uint64_t max_size = 0;
uint64_t old_time = UTUtilsGetSysTime();
uint64_t new_time = 0;
char buf[SEND_CHUNK_SIZE * 3] = {0};
while(1)
{
long size = uart_itf_get_can_read();
if (size > 0)
{
long len = uart_itf_recv(buf, (size > sizeof(buf)) ? sizeof(buf) : size);
total_bytes += len;
max_size = size > max_size ? size : max_size;
Report("t:%lld l:%ld %ld %ld\r\n", total_bytes, len, size, max_size);
old_time = new_time;
}
new_time = UTUtilsGetSysTime();
if (new_time - old_time > 800)
{
total_bytes = 0;
max_size = 0;
old_time = new_time;
}
}
}