我正在尝试为 PIC32MX320F128H 创建一个 UART 驱动程序,但是每当发生 IRQ 时,电路板就会在到达 ISR 之前崩溃。
为了测试我的理论,我手动将 RX 中断标志设置为 1 — 之后,它立即崩溃。如果我注释掉这一行,当启用 TX 中断时,板会稍后崩溃,因为该标志已经打开。下面是调试器在崩溃后停止的汇编代码。我在 ISR 的开头设置了断点,但实际上从未停止调试器。
还值得注意的是,如果单步调试各行,调试器将不会崩溃。只有当您实际按下运行按钮时它才会崩溃。这更加坚定了我的怀疑,即带有中断的东西是这个错误的根源。
crt0.S 第 118-120 行。这是来自 MPLABxIDE 的给定编译器(?不太确定)文件。
\_reset:
jal \_startup
nop
main() main() 还有更多内容,但它确实无关紧要,因为它永远不会达到这一点。 f IFS0 位.U1RXIF = 1;被注释掉,PutChar返回后板子会崩溃。
int main() {
unsigned char ReadChar;
int i, j;
// Init everything else
LEDS_INIT();
Uart_Init(115200);
// This will crash board.
IFS0bits.U1RXIF = 1;
// Turn on some LEDS, so we know board is working
LEDS_SET(0xC);
// Test if TX pin works
for(i = 0; i < 10; i++) {
// Send char and wait for transmit
U1TXREG = TEST_CHAR + i;
while(!U1STAbits.TRMT);
}
// Test if PutChar will send chars
for(i = 0; i < 10; i++) {
PutChar(TEST_CHAR + i + 5);
}
这是董事会设置
// BOARD Setup
\#pragma config POSCMOD = XT // Set oscillator to XT, crystal mode.
\#pragma config FPBDIV = DIV_2 // Set peripheral clock to run at half sys clock
\#pragma config FWDTEN = OFF // Disable watchdog timer
\#pragma config CP = OFF // Disable Code protect, ensures all memory is available
\#pragma config FPLLMUL = MUL_20 // PLL Multiplier
\#pragma config FPLLODIV = DIV_1 // System PLL Output Clock Divide
\#define SYSTEM_CLOCK 80000000L
\#define PB_CLOCK SYSTEM_CLOCK/2
\#define TRUE 1
\#define FALSE 0
// UART DEFINES
\#define UART_IBITS 0x1C000000 // ERR, RX, TX interrupt bits
\#define ERR_IBITS 0x4000000
\#define RX_IBITS 0x8000000
\#define TX_IBITS 0x10000000
\#define STA_OERR_BIT 2 // U1STA bit assosciated with OERR
\#define TEST_CHAR 0x41 // char to send and test stuff, A in ascii
\#define U1_PRIORITY 0b110 // don't know what this should be
\#define U1_SUBPRIORITY 0b01 // don't know what this should be either
这里是UART设置,以及中断设置。
void Uart_Init(unsigned long baudRate) {AD1PCFG = 0xffff; // Set PORTs to digital mode
// Disable interrupts to avoid crazy malloc errors while initing CBuffs
__builtin_disable_interrupts();
// Initialize CBuffers
RXBuff = InitCBuff();
TXBuff = InitCBuff();
// Enable interrupts after cbuffs are initialized
__builtin_enable_interrupts();
// Disable stdout to UART2
setbuf(stdout, NULL);
// Clear control registers
U1MODECLR = 1;
U1STACLR = 1;
// Clear RX, TX registers
U1RXREG = 0;
U1TXREG = 0;
// Set Baudrate, U1BRG should be 20 or 21. In this case it is 21.
U1MODEbits.BRGH = 0; // enable high baudrate mode
U1BRG = (PB_CLOCK / (16 * baudRate)) - 1;
// Turn on the UART
// Note, that by default the UART is configured for 8 data bits, 1 stop bit, and no parity.
U1MODEbits.ON = 1; // 8 bit 1 stop bit
// Enable RX and TX pins
U1STAbits.URXEN = 1;
U1STAbits.UTXEN = 1;
// Enable interrupts RX and ERR interrupts. TX will enable when TXBuff has chars
IEC0bits.U1RXIE = 1;
IEC0bits.U1EIE = 1;
IEC0bits.U1TXIE = 0;
// Set Interrupt priority and subpriority
IPC6bits.U1IP = U1_PRIORITY;
IPC6bits.U1IS = U1_SUBPRIORITY;
// Set interrupt modes
U1STAbits.URXISEL = 0b00; // flag when char received
U1STAbits.UTXISEL = 0b10; // flag when buffer is empty
}
ISR,即使传递了ILP6AUTO参数也会崩溃:
void __ISR(_UART1_VECTOR) IntUart1Handler(void) {
// Tell me interrupt is on
LATE = 0xFF;
// Check if chars are in RX
if(U1STAbits.URXDA) {
CBWriteChar(RXBuff, U1RXREG);
}
// Check if TX is empty & chars need to be sent
if((!U1STAbits.UTXBF) && (TXBuff->state == WORKING)) {
// read from buffer and write to TX
// need to investigate what happens if null is returned
// may be worth the time to include check for null
U1TXREG = CBReadChar(TXBuff);
}
// Check if TXBuff is empty to turn off TX interrupt
if (TXBuff->state == EMPTY) {
IEC0bits.U1TXIE = 0;
}
// Clearing OERR every time is less expensive than a check every time
// It might just clear RX every time. Investigate after driver works
if (U1STAbits.OERR == 1) {
U1STACLR = STA_OERR_BIT;
}
// Clear interrupts
IFS0bits.U1EIF = 0;
IFS0bits.U1RXIF = 0;
IFS0bits.U1TXIF = 0;
}
这里是 PutChar(),它在 BOARD 崩溃之前到达 return TRUE 语句。也就是说,如果程序甚至到达 PutChar(),则需要将
IFS0bits.U1RXIF = 1;
注释掉。
int PutChar(char ch) {
// Write to TXBuffer, check full
if(CBWriteChar(TXBuff, ch)) {
return FALSE;
}
// Turn on TX interrupt AFTER char is written to
IEC0bits.U1TXIE = 1;
// if not full, return good
return TRUE;
}
我不知道会发生什么。我很欣赏任何有关可能出现问题的见解。请随时询问更多信息,我会尽快回复。
我没有正确启用中断。以下是我按照本指南启用 UART 中断的方法。
实际上只有七个步骤。步骤 3 到 7 应在您的程序中按顺序完成。
以下是我按照以下步骤配置 UART 的方法。
#include <xc.h>
#include <sys/attribs.h>
void Uart_Init(unsigned long baudRate) {
// Set Ports to digital mode, configure later to only do UART pins.
AD1PCFG = 0xffff;
// Initialize CBuffers
RXBuff = InitCBuff();
TXBuff = InitCBuff();
// Clear control registers
U1MODECLR = 0xFF;
U1STACLR = 0xFF;
// Clear RX, TX registers
U1RXREG = 0;
U1TXREG = 0;
// Set Baudrate, U1BRG should be 20 or 21. In this case it is 21.
U1MODEbits.BRGH = 0; // enable high baudrate mode
U1BRG = (PB_CLOCK / (16 * baudRate)) ;
// Turn off the UART
U1MODEbits.ON = 0;
// Enable RX and TX pins
U1STAbits.URXEN = 1;
U1STAbits.UTXEN = 1;
// Set interrupt modes
U1STAbits.URXISEL = 0b00; // flag when char received
U1STAbits.UTXISEL = 0b10; // flag when buffer is empty
// Set Interrupt priority and sub-priority
IPC6bits.U1IP = 4;
IPC6bits.U1IS = 1;
// Clear flags
IFS0bits.U1EIF = 0;
IFS0bits.U1RXIF = 0;
IFS0bits.U1TXIF = 0;
// Enable interrupts RX and ERR interrupts. TX not necessary for this simple program
IEC0bits.U1RXIE = 1;
IEC0bits.U1EIE = 1;
IEC0bits.U1TXIE = 0;
// Enable multi-vector interrupts
INTCONSET = _INTCON_MVEC_MASK;
// Enable Global Interrupts
__builtin_enable_interrupts();
// Enable UART
// Note, that by default the UART is configured for 8 data bits, 1 stop bit, and no parity.
U1MODEbits.ON = 1;
}