简体   繁体   English

PIC18 上的多个 SPI 配置

[英]Multiple SPI configurations on PIC18

I am using the PIC18f46k42 microcontroller, XC8 2.3, with MPLABX/ MCC.我正在使用带有 MPLABX/MCC 的 PIC18f46k42 微控制器 XC8 2.3。 My goal is to use the single SPI hardware peripheral to interface with multiple devices using various GPIO pins as chip selects.我的目标是使用单个 SPI 硬件外设与使用各种 GPIO 引脚作为芯片选择的多个设备连接。 I have an LCD and an SD card that both need to talk to the MCU (obv not at the same time).我有一个 LCD 和一个 SD 卡,它们都需要与 MCU 通信(不是同时)。 My issue is when I try to change the SPI hardware configuration registers to switch between devices.我的问题是当我尝试更改 SPI 硬件配置寄存器以在设备之间切换时。 So I tried reducing the problem and have come to this:因此,我尝试减少问题并得出以下结论:

If I only use one spi configuration to drive the screen, it works.如果我只使用一个spi配置来驱动屏幕,它就可以工作。 However if I try to close that spi connection and then reopen the same spi connection, the screen doesnt work.但是,如果我尝试关闭该 spi 连接,然后重新打开同一个 spi 连接,则屏幕不工作。 I believe the issue then lies in the SPI1_Open() generated by mcc.我认为问题在于 mcc 生成的 SPI1_Open()。

spi1.h: 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: 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;
}

main.c:主要.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
    }
}

I can include as well what's in ST7735.h/ST7735.c but I'm certain they are fine because they work just fine when spi1 is configured normally.我也可以包括 ST7735.h/ST7735.c 中的内容,但我确信它们很好,因为当 spi1 正常配置时它们工作得很好。 The poor behavior only starts when I try to toggle the spi configuration which I must do in order to inevitably toggle between multiple devices.只有当我尝试切换 spi 配置时才会开始出现不良行为,而我必须这样做才能不可避免地在多个设备之间切换。 In the above code, SPI is defaulted to EN=0.在上面的代码中,SPI 默认为 EN=0。 I can include the version where SPI is defaulted EN=1 and uses SPI1_Close() to toggle it off.我可以包含 SPI 默认为 EN=1 的版本,并使用 SPI1_Close() 将其关闭。 However both behave the same and this version is slightly simpler.然而,两者的行为相同,而且这个版本稍微简单一些。 I greatly appreciate any input you might have.我非常感谢您的任何意见。

I solved the issue myself.我自己解决了这个问题。

this is the offending function:这是违规的 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;
}

the line:该行:

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

should be just:应该只是:

SPI1CON2 = spi1_configuration[spi1UniqueConfiguration].con2;

this became apparent when looking at the initialize function, which works when the default state is enable (ie SPI1CON0 = 0x83):当查看初始化 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;
} 

this function which works correctly does not "or" SPI1CON2 with (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK).这个正常工作的 function 不会“或”SPI1CON2 与 (_SPI1CON2_SPI1RXR_MASK | _SPI1CON2_SPI1TXR_MASK)。

when tested, this behaves correctly.测试时,此行为正确。 credit to Oleg Mazurov, who's comment made me recheck the mcc generated code.感谢 Oleg Mazurov,他的评论让我重新检查了 mcc 生成的代码。 while the mcc generated code has never failed me before, if you are doing anything sufficiently advanced with mcc, I recommend checking it carefully before assuming it is working correctly.虽然 mcc 生成的代码以前从未让我失望过,但如果您正在使用 mcc 做任何足够高级的事情,我建议在假设它正常工作之前仔细检查它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM