簡體   English   中英

PIC18 上的多個 SPI 配置

[英]Multiple SPI configurations on PIC18

我正在使用帶有 MPLABX/MCC 的 PIC18f46k42 微控制器 XC8 2.3。 我的目標是使用單個 SPI 硬件外設與使用各種 GPIO 引腳作為芯片選擇的多個設備連接。 我有一個 LCD 和一個 SD 卡,它們都需要與 MCU 通信(不是同時)。 我的問題是當我嘗試更改 SPI 硬件配置寄存器以在設備之間切換時。 因此,我嘗試減少問題並得出以下結論:

如果我只使用一個spi配置來驅動屏幕,它就可以工作。 但是,如果我嘗試關閉該 spi 連接,然后重新打開同一個 spi 連接,則屏幕不工作。 我認為問題在於 mcc 生成的 SPI1_Open()。

spi1.h:

#ifndef SPI1_MASTER_H
#define SPI1_MASTER_H

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

/* SPI interfaces */
typedef enum { 
    SPI1_DEFAULT
} spi1_modes_t;

void SPI1_Initialize(void);
bool SPI1_Open(spi1_modes_t spi1UniqueConfiguration);
void SPI1_Close(void);
uint8_t SPI1_ExchangeByte(uint8_t data);
void SPI1_ExchangeBlock(void *block, size_t blockSize);
void SPI1_WriteBlock(void *block, size_t blockSize);
void SPI1_ReadBlock(void *block, size_t blockSize);
void SPI1_WriteByte(uint8_t byte);
uint8_t SPI1_ReadByte(void);

#endif //SPI1_H

spi1.c:

#include "spi1.h"
#include <xc.h>

typedef struct { 
    uint8_t con0; 
    uint8_t con1; 
    uint8_t con2; 
    uint8_t baud; 
    uint8_t operation;
} spi1_configuration_t;


//con0 == SPIxCON0, con1 == SPIxCON1, con2 == SPIxCON2, baud == SPIxBAUD, operation == Master/Slave
static const spi1_configuration_t spi1_configuration[] = {   
    { 0x3, 0x60, 0x2, 0x3, 0 }
};

void SPI1_Initialize(void)
{
    //EN disabled; LSBF MSb first; MST bus master; BMODE every byte; 
    SPI1CON0 = 0x03;
    //SMP Middle; CKE Active to idle; CKP Idle:High, Active:Low; FST disabled; SSP active high; SDIP active high; SDOP active high; 
    SPI1CON1 = 0x60;
    //SSET disabled; TXR required for a transfer; RXR data is not stored in the FIFO; 
    SPI1CON2 = 0x02;
    //CLKSEL FOSC; 
    SPI1CLK = 0x00;
    //BAUD 3; 
    SPI1BAUD = 0x03;
    TRISCbits.TRISC1 = 0;
}

bool SPI1_Open(spi1_modes_t spi1UniqueConfiguration)
{
    if(!SPI1CON0bits.EN)
    {
        SPI1CON0 = spi1_configuration[spi1UniqueConfiguration].con0;
        SPI1CON1 = spi1_configuration[spi1UniqueConfiguration].con1;
        SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2 | (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK);
        SPI1CLK  = 0x00;
        SPI1BAUD = spi1_configuration[spi1UniqueConfiguration].baud;        
        TRISCbits.TRISC1 = spi1_configuration[spi1UniqueConfiguration].operation;
        SPI1CON0bits.EN = 1;
        return true;
    }
    return false;
}

void SPI1_Close(void)
{
    SPI1CON0bits.EN = 0;
}

uint8_t SPI1_ExchangeByte(uint8_t data)
{
    SPI1TCNTL = 1;
    SPI1TXB = data;
    while(!PIR2bits.SPI1RXIF);
    return SPI1RXB;
}

void SPI1_ExchangeBlock(void *block, size_t blockSize)
{
    uint8_t *data = block;
    while(blockSize--)
    {
        SPI1TCNTL = 1;
        SPI1TXB = *data;
        while(!PIR2bits.SPI1RXIF);
        *data++ = SPI1RXB;
    }
}

// Half Duplex SPI Functions
void SPI1_WriteBlock(void *block, size_t blockSize)
{
    uint8_t *data = block;
    while(blockSize--)
    {
        SPI1_ExchangeByte(*data++);
    }
}

void SPI1_ReadBlock(void *block, size_t blockSize)
{
    uint8_t *data = block;
    while(blockSize--)
    {
        *data++ = SPI1_ExchangeByte(0);
    }
}

void SPI1_WriteByte(uint8_t byte)
{
    SPI1TXB = byte;
}

uint8_t SPI1_ReadByte(void)
{
    return SPI1RXB;
}

主要.c:

#include "mcc_generated_files/mcc.h"
#include "ST7735.h"

#define led0 PORTAbits.RA7
#define led1 PORTAbits.RA6
#define led2 PORTAbits.RA5
#define led3 PORTAbits.RA4

void main(void)
{
    // Initialize the device
    SYSTEM_Initialize();
    
    led0 = SPI1_Open(SPI1_DEFAULT);
    led0 = SPI1CON0bits.EN;
    
    LCD_RESET = 1;
    delay_us(500);
    LCD_RESET = 0;
    delay_us(500);
    LCD_RESET = 1;
    delay_us(500);
    
    __delay_ms(1000);
    
    ST7735_initR();
    ST7735_fillScreen(ST7735_BLACK);

    while (1)
    {
        // Add your application code
    }
}

我也可以包括 ST7735.h/ST7735.c 中的內容,但我確信它們很好,因為當 spi1 正常配置時它們工作得很好。 只有當我嘗試切換 spi 配置時才會開始出現不良行為,而我必須這樣做才能不可避免地在多個設備之間切換。 在上面的代碼中,SPI 默認為 EN=0。 我可以包含 SPI 默認為 EN=1 的版本,並使用 SPI1_Close() 將其關閉。 然而,兩者的行為相同,而且這個版本稍微簡單一些。 我非常感謝您的任何意見。

我自己解決了這個問題。

這是違規的 function:

bool SPI1_Open(spi1_modes_t spi1UniqueConfiguration)
{
    if(!SPI1CON0bits.EN)
    {
        SPI1CON0 = spi1_configuration[spi1UniqueConfiguration].con0;
        SPI1CON1 = spi1_configuration[spi1UniqueConfiguration].con1;
        SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2 | (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK);
        SPI1CLK  = 0x00;
        SPI1BAUD = spi1_configuration[spi1UniqueConfiguration].baud;        
        TRISCbits.TRISC1 = spi1_configuration[spi1UniqueConfiguration].operation;
        SPI1CON0bits.EN = 1;
        return true;
    }
    return false;
}

該行:

SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2 | (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK);

應該只是:

SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2;

當查看初始化 function 時,這一點變得很明顯,它在啟用默認 state 時起作用(即 SPI1CON0 = 0x83):

void SPI1_Initialize(void)
{
    //EN disabled; LSBF MSb first; MST bus master; BMODE every byte; 
    SPI1CON0 = 0x03;
    //SMP Middle; CKE Active to idle; CKP Idle:High, Active:Low; FST disabled; SSP active high; SDIP active high; SDOP active high; 
    SPI1CON1 = 0x60;
    //SSET disabled; TXR required for a transfer; RXR data is not stored in the FIFO; 
    SPI1CON2 = 0x02;
    //CLKSEL FOSC; 
    SPI1CLK = 0x00;
    //BAUD 3; 
    SPI1BAUD = 0x03;
    TRISCbits.TRISC1 = 0;
} 

這個正常工作的 function 不會“或”SPI1CON2 與 (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK)。

測試時,此行為正確。 感謝 Oleg Mazurov,他的評論讓我重新檢查了 mcc 生成的代碼。 雖然 mcc 生成的代碼以前從未讓我失望過,但如果您正在使用 mcc 做任何足夠高級的事情,我建議在假設它正常工作之前仔細檢查它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM