先說下CC3200存在2個16*8的fifos, 分別用于發送和接收
當fifos被disable時,將會作為一個1字節深度的保持寄存器,
所以無論fifos是開是關,發送和接收都繞不開fifos
DMA
由于發送和接收都繞不過fifos,所以DMA也繞不開FIFOS.
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 μDMA
event. 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
// 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");}}
voidInitUART0Transfer(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全速接收串口數據
// 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;}}
}