中断发生时PIC32MX崩溃

问题描述 投票:0回答:1

我正在尝试为 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;
}

我不知道会发生什么。我很欣赏任何有关可能出现问题的见解。请随时询问更多信息,我会尽快回复。

c embedded interrupt pic pic32
1个回答
0
投票

我没有正确启用中断。以下是我按照本指南启用 UART 中断的方法。

实际上只有七个步骤。步骤 3 到 7 应在您的程序中按顺序完成。

  1. 包括 xc.h 和 sys/attribs.h
  2. 创建 ISR。确保此处的优先级参数与中断配置中指定的优先级匹配。
  3. 关闭外围设备。
  4. 配置中断,按以下顺序:设置优先级,设置子优先级,清除标志,然后启用中断
  5. 启用多向量中断。
  6. 启用全局中断
  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;
}
© www.soinside.com 2019 - 2024. All rights reserved.