我有一个带有资源管理器板16的dsPIC33。整个代码库相当冗长,但问题与DMA中断隔离。即使我已经复制了Microchip UARTloopback示例,它也没有被触发。我已经完全阅读了关于UART和DMA的Microchip手册部分,并且环回示例确实有效,但是当使用我的代码实现它时它没有。我检查了我的整个项目,以确保DMA通道不会被覆盖或在项目的其他任何地方使用。这同样适用于UART部分。我将包括整个文件c文件和h文件。要关注的函数是uart_commInit,BEACON_uart_commPuts和_DMA3Interrupt。 BEACON_uart_commPuts工作并打印到终端。一切都在编译
uart.c
/**
* This source file contains functions for using the UARTs.
*
* @todo Write uart_monitor() or ISR to check for UART parity, framing error and DMA collisions
*
* @ingroup CSuart
* @defgroup CSuart UART
* @{
* High level functions for UART with DMA. Function names
* beginning with uart_comm... are for communicating with the transceiver. The
* UART peripheral used for the transceiver can be changed by editing the macros
* in CSuart.h.
*/
/* System & Local Includes */
#include <p33Fxxxx.h>
#include <string.h>
#include "CSdefine.h"
#include "types.h"
#include "CSuart.h"
/* Type and Constant Definitions*/
// Handshake control signals for Devboard USB
#define HS0 BIT4 // RC4
#define HS1 BIT3 // RC3
#define HS2 BIT2 // RC2
#define HS3 BIT5 // RD5
#define HS4 BIT2 // RD2
#define HS5 BIT1 // RD1
// Motherboard control signals
#define CS_SD_BAR BIT5 // RE5
#define OE_USB_BAR BIT1 // RC1
#define OE_MHX_BAR BIT2 // RE2
#define ON_SD_BAR BIT4 // RE4
#define ON_MHX_BAR BIT3 // RE3
/* Global & Local Variables */
// DMA TX and RX buffers for comm UART
static uint16 txBuff[RADIO_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 rxBuff[RADIO_RX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 tx0Buff[BEACON_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 rx0Buff[BEACON_TX_BUFFER_SIZE] __attribute__((space(dma)));
static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read from DMA rxBuff
static uint16 *lastRead0 = (uint16 *) &rx0Buff; // Points to next transfer to be read from DMA rxBuff
/* Functions */
/******************************************************************************
**** ****
** **
csk_usb_open() Enable USB on the Dev/Flight hardware
** **
**** ****
******************************************************************************/
void csk_usb_open(void) {
// Disable all control signals to avoid spurious
// writes when -OE_USB goes active (LOW).
PORTD |= (HS5+HS4+HS3 );
TRISD &= ~(HS5+HS4+HS3 );
//
// // Configure -OE_USB as an output, and make
// // it active (i.e., LOW)
PORTC &= ~OE_USB_BAR;
TRISC &= ~OE_USB_BAR;
} /* csk_usb_open() */
/******************************************************************************
**** ****
** **
csk_usb_close() // Disable USB on the Dev/flight hardware
** **
**** ****
******************************************************************************/
void csk_usb_close(void) {
// Restore -OE_USB to an input.
PORTC |= OE_USB_BAR;
TRISC |= OE_USB_BAR;
} /* csk_usb_close() */
/**
* Initializes the UART port with DMA for use for satellite comm (ie. the transceiver).
* This should be called sometime during startup.
*/
void uart_commInit(){
// Configure UART for 9600 8N1 with interrupts to the DMA module
RADIO_UMODEbits.UEN = 0b10; //UxTX, UxRX, UxCTS and UxRTS pins are enabled and used
RADIO_UMODEbits.PDSEL = 0b00; //8-bit data, no parity
RADIO_UBRG = ((Fcyc/38400)/16)-1; //9600 baud //38400 //((Fcyc/38400)/16)-1
//COMM_UBRG = 259; // 9600 baud @ 80MHz
RADIO_USTAbits.UTXISEL0 = 0; // Interrupt when there is room in TX FIFO
RADIO_USTAbits.URXISEL = 0; // Interrupt when a character is received
// Configure DMA channel 1 as Comm Uart transmit
DMA1CONbits.DIR = 1; // DMA reads from SRAM, writes to peripheral
DMA1CONbits.AMODE = 00; // Addr. mode is register indirect w/ post increment
DMA1CONbits.MODE = 0b01;// One-shot, no ping-pong mode.
DMA1CONbits.SIZE = 1; // Transfer 1 byte at a time
DMA1REQbits.IRQSEL = 0b0001100; // DMA1 writes to UART1 TX (the Comm uart port.)
DMA1PAD = (volatile unsigned int) &RADIO_UTXREG; //Tell DMA module address of COMM TX register
DMA1STA = __builtin_dmaoffset(txBuff); // Tell DMA module start address of our dma tx buffer
IFS0bits.DMA1IF = 0; // Clear DMA interrupt flag
//IEC0bits.DMA1IE = 1; // Enable DMA interrupt
//Configure DMA channel 0 as Comm Uart receive
DMA0CONbits.MODE = 0b00; // Continuous no Ping-Pong mode
DMA0CNT = RADIO_RX_BUFFER_SIZE - 1;
DMA0REQbits.IRQSEL = 0b0001011; // DMA0 reads from UART1 RX (the Comm uart port.)
DMA0PAD = (volatile unsigned int) &RADIO_URXREG;
DMA0STA = __builtin_dmaoffset(rxBuff); // Tell DMA start addr. of buffer A
//DMA0STB = __builtin_dmaoffset(rxBuffB); // Tell DMA start addr. of buffer B
IFS0bits.DMA0IF = 0; // Clear DMA interrupt flag
//IEC0bits.DMA0IE = 1; // Enable DMA interrupt
DMA0CONbits.CHEN = 1; // Enable RX DMA channel only. TX channel is one-shot mode.
// UART config for CLI
BEACON_UMODEbits.STSEL = 0; //1-stop bit
BEACON_UMODEbits.PDSEL = 0; //No Parity, 8-data bits
BEACON_UMODEbits.ABAUD = 0; // Autobaud Disabled
BEACON_UBRG = ((Fcyc/9600)/16)-1; // 9600 baud @ 80Mhz
BEACON_USTAbits.UTXISEL0 = 0; // interrupt after 1 Tx char is transmited
//BEACON_USTAbits.UTXISEL1 = 0;
BEACON_USTAbits.URXISEL = 0; // interrrupt after 1 Rx char is received
BEACON_UMODEbits.UARTEN = 1; // Enable UART
BEACON_USTAbits.UTXEN = 1; // Enable Uart Tx
IEC4bits.U2EIE = 0; // Enable error interrupt
//Tx config for CLI
DMA4REQ = 0x001F; // Uart2 transmiter
DMA4PAD = (volatile unsigned int) &BEACON_UTXREG;// Tell DMA module address of COMM TX register
DMA4CONbits.AMODE = 0; // Addr. mode is register indirect x/ post increment
DMA4CONbits.MODE = 1; // One-Shot
DMA4CONbits.DIR = 1; // reads from RAM writes to peripheral
DMA4CONbits.SIZE = 1;// Transfers 1 byte at a time
// count needs to be pushed into interrupt and counted there, will avoid weird shit
DMA4CNT = 7; // 11 DMA requests
DMA4STA = __builtin_dmaoffset(tx0Buff); // Tell DMA module start address of our dma tx buffer
IFS2bits.DMA4IF = 0; // Clear DMA interrupt flag
IEC2bits.DMA4IE = 1; // Enable DMA interrupt
// Rx config for CLI
DMA3REQ = 0x001E; // Uart2 Receive
DMA3PAD = (volatile unsigned int) &BEACON_URXREG; // Tell DMA module address of COMM RX register
DMA3CONbits.AMODE = 0; // Addr. mode is register indirect x/ post increment
DMA3CONbits.MODE = 2; // Ping-Pong
DMA3CONbits.DIR = 0; // reads from peripheral writes to RAM
DMA3CONbits.SIZE = 0; // Transfers 1 word at a time
DMA3CNT = 7; // 11 DMA requests
DMA3STA = __builtin_dmaoffset(tx0Buff); // Tell DMA start addr. of receive buffer
DMA3STB = __builtin_dmaoffset(rx0Buff); // Tell DMA start addr. of receive buffer
DMA3CONbits.CHEN = 1; // Enable RX DMA channel only. TX channel is one-shot mode.
IFS2bits.DMA3IF = 0; // Clear DMA interrupt
IEC2bits.DMA3IE = 1; // Enable DMA interrupt
// END of added code
// these bits must be at end of file
RADIO_UMODEbits.UARTEN = 1; //enable uart
RADIO_USTAbits.UTXEN = 1; //transmit enabled
}
/**
* Writes a string to the comm Port. The length must be less than COMM_TX_BUFFER_SIZE
* or this function will have no effect.
* @param str The string to write.
* @param len The number of bytes to write
* @pre uart_commInit() must be called before calling this function.
* @note This function call is blocking. It waits until the last transfer is
* finished to begin current transmission. Once current transmission has been
* started then it will return because the DMA module handles transmission of data.
*/
void BEACON_uart_commPuts(char *str, uint16 len){
#if DEBUG_OUTPUT
uint16 *targetAddr;
if(len == 0 || len > BEACON_TX_BUFFER_SIZE)
return; //TODO Handle error
while(!BEACON_commIsTXReady()); // Blocking!
targetAddr = (uint16 *) (DMA4STA + ((unsigned int) &_DMA_BASE)); // Address of DMA buffer
memcpy((void *) targetAddr, (const void *) str, len); // Copy data into DMA buffer
DMA4CNT = len-1; // Send len # of characters
DMA4CONbits.CHEN = 1; // Turn on the DMA channel
DMA4REQbits.FORCE = 1; // Start DMA transfer to comm UART
#endif
}
/**
* Retrieves a string from the Comm. Port. The caller must ensure that the 'str'
* parameter can handle the number of bytes being requested in parameter 'len'.
* @param str The string to store the received characters in.
* @param len The maximum number of characters to return. The number of chars
* copied to str will be less than or equal to len.
* @return int16 The number of bytes copied to str if non-negative or an error
* code if negative.
* @pre uart_commInit() must be called before calling this function.
* @todo Add overrun detection
* @todo Implement error codes if necessary.
*/
int16 RADIO_uart_commGets(char *str, uint16 len){
/* The DMA transfers 2 bytes of data into the DMA buffer for every byte it
* receives from the UART (see dsPIC33 reference manual DMA chapter). The
* lower byte is the data received by the UART and the upper byte has 2
* status bits. There is one DMA receive buffer (no Ping-Pong mode) which the
* DMA starts to fill 2 bytes at a time until the buffer is full then goes
* back to the beginning and starts to put new characters in the beginning
* of the buffer again. This code reads up to 'len' bytes (not transfers!) from the buffer
* starting from the last location readmup to the last byte available in
* the DMA buffer. If the DMA rolled over to the beginning since the last read,
* this function reads until the end of the buffer, then from the beginning.
* This should be called often enough to prevent overruns.
*
* NOTE: For every 2 bytes this function reads from the DMA buffer it only
* returns one because the upper byte of each transfer are status bits.
*/
uint16 numTransfers, i; // # of DMA transfers (not bytes!) to return to caller.
uint16 *lastArrived = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
//static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read
if(lastArrived < lastRead){ // Rollover occured
// (1) # of transfers till end of buffer.
// (2) # of transfers in the beginning of buffer.
numTransfers = (uint16) ((rxBuff + RADIO_RX_BUFFER_SIZE - 1) - lastRead);
numTransfers += (uint16) (lastArrived - rxBuff);
}else{
numTransfers = (uint16) (lastArrived - lastRead);
}
if(len < numTransfers) // Don't give caller more bytes than they can handle
numTransfers = len;
for(i = 0; i < numTransfers; i++){ // Now copy chars into caller's buffer
/*if(i == 0){
uart_commGetc();
continue;
}*/
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rxBuff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to callers buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return i; // # of bytes returned in parameter 1.
}
int16 BEACON_uart_commGets(char *str, uint16 len){
/* The DMA transfers 2 bytes of data into the DMA buffer for every byte it
* receives from the UART (see dsPIC33 reference manual DMA chapter). The
* lower byte is the data received by the UART and the upper byte has 2
* status bits. There is one DMA receive buffer (no Ping-Pong mode) which the
* DMA starts to fill 2 bytes at a time until the buffer is full then goes
* back to the beginning and starts to put new characters in the beginning
* of the buffer again. This code reads up to 'len' bytes (not transfers!) from the buffer
* starting from the last location readmup to the last byte available in
* the DMA buffer. If the DMA rolled over to the beginning since the last read,
* this function reads until the end of the buffer, then from the beginning.
* This should be called often enough to prevent overruns.
*
* NOTE: For every 2 bytes this function reads from the DMA buffer it only
* returns one because the upper byte of each transfer are status bits.
*/
uint16 numTransfers, i; // # of DMA transfers (not bytes!) to return to caller.
uint16 *lastArrived = (uint16 *)(DMA3STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
//static uint16 *lastRead = (uint16 *) &rxBuff; // Points to next transfer to be read
if(lastArrived < lastRead){ // Rollover occured
// (1) # of transfers till end of buffer.
// (2) # of transfers in the beginning of buffer.
numTransfers = (uint16) ((rx0Buff + BEACON_RX_BUFFER_SIZE - 1) - lastRead);
numTransfers += (uint16) (lastArrived - rx0Buff);
}else{
numTransfers = (uint16) (lastArrived - lastRead);
}
if(len < numTransfers) // Don't give caller more bytes than they can handle
numTransfers = len;
for(i = 0; i < numTransfers; i++){ // Now copy chars into caller's buffer
/*if(i == 0){
uart_commGetc();
continue;
}*/
if(lastRead >= rx0Buff + BEACON_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rx0Buff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to callers buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return i; // # of bytes returned in parameter 1.
}
/**
* Retrieves a single character from the comm receive buffer.
* @return (int16) returns a signed integer. If the value is less than zero there
* were no characters in the UART receive buffer to return. Otherwise, the return
* value should be cast to a char and used accordingly.
* @pre uart_commInit() must be called before calling this function.
*/
int16 RADIO_uart_commGetc(){
int16 retValue;
if(RADIO_uart_commNumRXBytes() > 0){
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rxBuff; // Start reading from beginning now
}
retValue = (int16) *lastRead;
lastRead++;
return retValue;
}
return -1;
}
/**
* Retrieves a single character from the comm receive buffer.
* @return (int16) returns a signed integer. If the value is less than zero there
* were no characters in the UART receive buffer to return. Otherwise, the return
* value should be cast to a char and used accordingly.
* @pre uart_commInit() must be called before calling this function.
*/
int16 BEACON_uart_commGetc(){
int16 retValue;
if(BEACON_uart_commNumRXBytes() > 0){
if(lastRead >= rx0Buff + BEACON_RX_BUFFER_SIZE){ // Handle rollover
lastRead = rx0Buff; // Start reading from beginning now
}
retValue = (int16) *lastRead;
lastRead++;
return retValue;
}
return -1;
}
/**
* Looks for and retrieves a string from the comm port up to and including the
* specified terminating character. If the terminating character does not exist
* in the uart buffer no characters are copied to str and -1 is returned.
* @param str A buffer to stored the received data in
* @param len Maximum number of characters to retrieve
* @param terminator the terminating character
* @return The number of characters copied to str, -1 if no terminator not found or buffer to small for command
*/
int16 uart_commGetToChar(char *str, uint16 len, char terminator){
BOOL foundChar = FALSE;
int16 i, strLen = 0; // strLen is the value we will return
uint16 *tempPtr = lastRead; // Points after the last read DMA transfer (transfer = 2 bytes)
uint16 *lastArrived = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE)); // Points after most recent transfer received in DMA buffer
len = (len < (i = RADIO_uart_commNumRXBytes())) ? len : i; // If numCharsReceived > len then len = numCharsReceived
// Look for null terminating character
while(!foundChar){ // Loop until char is found or 'till end of received chars
if(strLen >= len){
return -1; // Provided buffer not long enough or terminating char not found.
}
if((char) (*tempPtr & 0xFF) == terminator){ // Found terminating char?
foundChar = TRUE;
strLen++; // To count terminating character
}else{
strLen++; // Increment # of transfers we're planning to copy to user's buffer
tempPtr++; // Increment pointer to the receive buffer
if(tempPtr >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover in rxBuff
tempPtr = rxBuff; // Start reading from beginning now
}
}
}
for(i = 0; i < strLen; i++){ // Now copy chars into caller's buffer
if(lastRead >= rxBuff + RADIO_RX_BUFFER_SIZE){ // Handle rollover in rxBuff
lastRead = rxBuff; // Start reading from beginning now
}
// Mask off status byte and only copy the lower char to caller's buffer
*str = (char) (*lastRead & 0xFF);
str++; // Increment index into caller's buffer
lastRead++; // Increment read index
}
return strLen; // # of bytes INCLUDING terminating character
}
/**
* Returns the number of unread characters in the comm UART buffer.
* @return (int16) number of unread chars in comm UART buffer
* @pre uart_commInit() must be called before calling this function.
*/
int16 RADIO_uart_commNumRXBytes(){
int16 retValue;
uint16 *lastReceivedChar = (uint16 *)(DMA0STA + ((unsigned int) &_DMA_BASE));
if(lastReceivedChar >= lastRead){
return (int16) (lastReceivedChar - lastRead);
}else{
retValue = (int16) ((uint16 *)(&rxBuff + RADIO_TX_BUFFER_SIZE) - lastRead);
retValue += (uint16) (lastReceivedChar - (uint16 *)&rxBuff);
return retValue;
}
}
int16 BEACON_uart_commNumRXBytes(){
int16 retValue;
uint16 *lastReceivedChar = (uint16 *)(DMA2STA + ((unsigned int) &_DMA_BASE));
if(lastReceivedChar >= lastRead){
return (int16) (lastReceivedChar - lastRead);
}else{
retValue = (int16) ((uint16 *)(&rx0Buff + BEACON_TX_BUFFER_SIZE) - lastRead);
retValue += (uint16) (lastReceivedChar - (uint16 *)&rx0Buff);
return retValue;
}
}
/* Interrupt Handlers */
//void __attribute__((__interrupt__,no_auto_psv)) _U2EInterrupt(void){
// TODO Handle Uart Error
//}
/**
* Comm receive DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA0Interrupt(void){
IFS0bits.DMA0IF = 0; // Clear DMA interrupt flag
}
/**
* Comm transmit DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA1Interrupt(void){
IFS0bits.DMA1IF = 0; // Clear DMA interrupt flag
}
/**
* Comm receive DMA interrupt service routine.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA3Interrupt(void){
static unsigned int BufferCount = 0;
if(BufferCount == 0){
DMA4STA = __builtin_dmaoffset(tx0Buff);
}
else{
DMA4STA = __builtin_dmaoffset(rx0Buff);
}
DMA4CONbits.CHEN = 1; // Re-enable DMA3 channel
DMA4REQbits.FORCE = 1; // manual start the transfers, if we doing predetermined transfer size
BufferCount ^= 1;
IFS2bits.DMA3IF = 0; // Clear DMA3 Interrupt flag
}
/**
* Comm transmit DMA interrupt service routine. Currently not used.
*/
void __attribute__((__interrupt__,no_auto_psv)) _DMA4Interrupt(void){
IFS2bits.DMA4IF = 0; // Clear DMA interrupt flag
}
/**
* @}
*/
uart.h
/**
* This header file provides function prototypes and macros for UART ports.
*
* @ingroup CSuart
*/
/**
* @ingroup CSuart
* @{
*/
#ifndef CSUART_H
#define CSUART_H
/* Include Files */
#include <p33Fxxxx.h>
/**
* Register definitions for Comm port uart
* Change these values to use the other uart port.
* WARNING: Must also change values in uart_commInit(). (DMA1REQbits.IRQSEL)
* @cond
*/
/*NOTE:(8/20/14, 3:53pm) these macros have been changed, U2 -> U1 */
#define RADIO_UMODE U1MODE
#define RADIO_UMODEbits U1MODEbits
#define RADIO_USTA U1STA
#define RADIO_USTAbits U1STAbits
#define RADIO_URXREG U1RXREG
#define RADIO_UTXREG U1TXREG
#define RADIO_UBRG U1BRG
#define RADIO_URXIF IFS0bits.U1RXIF // Comm uart receive interrupt flag
#define RADIO_UTXIF IFS0bits.U1TXIF // Comm uart transmite interrupt flag
#define RADIO_RXIntEnable() {IEC0bits.U1RXIE = 1;}
#define RADIO_TXIntEnable() {IEC0bits.U1TXIE = 1;}
#define RADIO_ErrorIntEnable() {IEC4bits.U1EIE = 1;}
#define RADIO_RXIntDisable() {IEC0bits.U1RXIE = 0;}
#define RADIO_TXIntDisable() {IEC0bits.U1TXIE = 0;}
#define RADIO_ErrorIntDisable() {IEC4bits.U1EIE = 0;}
#define BEACON_UMODEbits U2MODEbits
#define BEACON_USTAbits U2STAbits
#define BEACON_URXREG U2RXREG
#define BEACON_UTXREG U2TXREG
#define BEACON_UBRG U2BRG
#define BEACON_IFSbits IFS2bits
#define RADIO_TX_BUFFER_SIZE 283 /// Size of comm port's DMA transmit buffer in bytes
#define RADIO_RX_BUFFER_SIZE 128 /// Size of comm port's DMA receive buffer in bytes
#define BEACON_TX_BUFFER_SIZE 128 /// Size of comm port's DMA transmit buffer in bytes
#define BEACON_RX_BUFFER_SIZE 128 /// Size of comm port's DMA receive buffer in bytes
/**
* Returns 1 when the comm port UART is ready to transmit, and 0 otherwise.
*/
#define RADIO_commIsTXReady() (RADIO_USTAbits.TRMT)
#define BEACON_commIsTXReady() (BEACON_USTAbits.TRMT)
/* Function Prototypes */
void uart_commInit();
void BEACON_uart_commPuts(char *str, uint16 len);
void uart0_commPuts(char *str, uint16 len);
int16 RADIO_uart_commGets(char *str, uint16 len);
//int16 uart0_commGets(char *str, uint16 len);
int16 RADIO_uart_commGetc();
//int16 uart0_commGetc();
int16 uart_commGetToChar(char *str, uint16 len, char terminator);
//int16 uart0_commGetToChar(char *str, uint16 len, char terminator);
int16 RADIO_uart_commNumRXBytes();
//int16 uart0_commNumRXBytes();
/**
* @}
*/
#endif /* CSUART_H */