SPI 电子墨水显示器与 PIC 18F46K22 接口的问题

时间:2020-12-30 07:45:13

标签: c embedded pic spi pic18

我在 SPI 主模式下使用 PIC 18F46K22Waveshare 1.54" ePaper Module 通信。 FOSC 频率为内部 8Mhz,SPI 配置为 FOSC/4。因此,当我检查逻辑分析仪上的输出时,某些输出位与预期不同。并且SCL有一些偏差。

enter image description here

#include <xc.h>
#include "config.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "main.h"

//#define _XTAL_FREQ 8000000
#define SPI1_DUMMY_DATA 0x0
#define SPI_RX_IN_PROGRESS 0x0
#define MY_BUFFER_SIZE 25

extern UBYTE EPD_Init(const unsigned char* lut);


unsigned char myWriteBuffer[100]="Hi I'm master..";
uint8_t myReadBuffer[100];
uint8_t total;
uint8_t temp;
uint8_t my_data = 0x58;

void UART_Init(void)
{
    //69
    SPBRG2 = 69;

    TXSTA2bits.BRGH = 1;
    BAUDCON2bits.BRG16 = 1; // Divisor at 8 bit

    TRISDbits.TRISD6 = 0;
    TRISDbits.TRISD7 = 1;

    RCSTA2bits.SPEN = 1; // Enable serial port    
    TXSTA2bits.SYNC = 0; // Async operation

    TXSTA2bits.TX9 = 0; // No tx of 9th bit
    RCSTA2bits.RX9 = 0; // No rx of 9th bit

    TXSTA2bits.TXEN = 1; // Enable transmitter
    RCSTA2bits.CREN = 1; // Enable receiver    
}

void UART_Putch(unsigned char bt)
{
    while (!PIR3bits.TX2IF); // hold the program till TX buffer is free
    TXREG2 = bt; //Load the transmitter buffer with the received value
}

void UART_Print(unsigned const char *ptr)
{
    while (*ptr != 0)
    {
        UART_Putch(*ptr++);
    }
}

unsigned char UART_getch() {
    unsigned char temp;
    if (RCSTA2bits.OERR) // check for Error 
    {
        RCSTA2bits.CREN = 0; //If error -> Reset
        //__delay_ms(10);
        RCSTA2bits.CREN = 1; //If error -> Reset 
    }
    while (!PIR3bits.RC2IF); // hold the program till RX buffer is free

    temp = RCREG2;
    return temp; //receive the value and send it to main function
}

void main() 
{
    ANSELA = 0;
    ANSELB = 0;
    ANSELC = 0;
    ANSELD = 0;
    
    TRISBbits.TRISB0 = 0; //RST Pin OUTPUT
    TRISBbits.TRISB1 = 0; //DC Pin OUTPUT
    TRISBbits.TRISB2 = 0; //CS Pin OUTPUT
    
    TRISBbits.RB3 = 1;  //BUSY Pin INPUT
        
//    int i;
    
    TRISD =0;/* PORT initialize as output */
    
    EPD_RST_PIN = 0;
    EPD_DC_PIN = 0;
     
    //OSCCON = 0x72;        /* Use internal osc. frequency 16 MHz */    
    
    OSCCONbits.SCS = 0b10;          //Frequency & PLL SETUP
    OSCCONbits.IRCF = 0b110;        //8 MHz
    while (!OSCCONbits.HFIOFS);
    
    OSCTUNEbits.PLLEN = 0;          //PLL disable

    
    UART_Init();


    
    SPI_Init_Master();      /* Initialize SPI communication as a master */   
    

  
    if(EPD_Init(lut_full_update) != 0) {
        UART_Print("e-Paper init failed\r\n");
        while(1);
    }
    UART_Print("e-Paper init\r\n");
    for(uint8_t i = 0; i < 10; i++){
    __delay_ms(10);
    }


    EPD_Clear();
    UART_Print("e-Paper cleared\r\n");
       for(uint8_t i = 0; i < 10; i++){
    __delay_ms(50);
    }
    

    while(1)
    {

        

//        total = 0;
//        //do
//        //{
//            LATAbits.LATA5=0;
//            //total = SPI1_Exchange8bitBuffer(SPI1_DUMMY_DATA, MY_BUFFER_SIZE, &myReadBuffer[total]);
//            total = SPI1_Exchange8bit(my_data);
//            
//            LATAbits.LATA5=1;
//            __delay_ms(500);
//            __delay_ms(500);
//            // Do something else...
//
//        //} while(total < MY_BUFFER_SIZE);
//            //while(1);
//           
//         EPD_Clear();
//    
//    __delay_ms(500);
    }
}

void SPI_Init_Master()
{
    /* PORT definition for SPI pins*/    
    TRISCbits.TRISC4 = 1;   /* RB0 as input(SDI) */
    TRISCbits.TRISC3 = 0;   /* RB1 as output(SCK) */
//    TRISBbits.TRISB2 = 0; /* RA5 as a output(SS') */
    TRISCbits.TRISC5 = 0;   /* RC7 as output(SDO) */

    /* To initialize SPI Communication configure following Register*/
    EPD_CS_PIN = 1;
    SSP1STAT=0x00;      /* Data change on rising edge of clk , BF=0*/
    SSP1CON1=0x20;      /* Slave mode,Serial enable, idle state high for clk */ 
    PIR1bits.SSP1IF=0;
    /* Disable the ADC channel which are on for multiplexed pin
    when used as an input */    
    ADCON0=0;           /* This is for de-multiplexed the SCL
                and SDI from analog pins*/
    ADCON1=0x0F;        /* This makes all pins as digital I/O */    
}

uint8_t SPI1_Exchange8bit(uint8_t data)
{
    // Clear the Write Collision flag, to allow writing
    SSP1CON1bits.WCOL = 0;

    SSP1BUF = data;

    while(SSP1STATbits.BF == SPI_RX_IN_PROGRESS)
    {
    }

    return (SSP1BUF);
}

uint8_t SPI1_Exchange8bitBuffer(uint8_t *dataIn, uint8_t bufLen, uint8_t *dataOut)
{
    uint8_t bytesWritten = 0;

    if(bufLen != 0)
    {
        if(dataIn != NULL)
        {
            while(bytesWritten < bufLen)
            {
                if(dataOut == NULL)
                {
                    SPI1_Exchange8bit(dataIn[bytesWritten]);
                }
                else
                {
                    dataOut[bytesWritten] = SPI1_Exchange8bit(dataIn[bytesWritten]);
                }

                bytesWritten++;
            }
        }
        else
        {
            if(dataOut != NULL)
            {
                while(bytesWritten < bufLen )
                {
                    temp = SPI1_Exchange8bit(SPI1_DUMMY_DATA);
                    
                    if(temp!=SPI1_DUMMY_DATA)
                    {
                        UART_Putch(temp);  //uart print
                        dataOut[bytesWritten] = temp;
                        bytesWritten++;
                    }
                    __delay_ms(5);
                }
            }
        }
    }

    return bytesWritten;
}

1 个答案:

答案 0 :(得分:2)

将您的逻辑分析仪 SCK 和 MOSI 时序与为 https://www.waveshare.com/wiki/1.54inch_e-Paper_Module 处的部件指定的时序进行比较: enter image description here

请注意,MOSI (SDIN) 状态必须在 SCK (SCLK) 的上升沿保持稳定。在您的情况下,MOSI 转换与上升沿同步,并且在 MOSI 具有正确的 D7=0 状态之前,您有一个时钟转换。 SPI 时序由时钟极性和时钟相位定义 - 提供四种可能的时钟模式。将 Waveshare 时序图与 18F46K22 datasheet 进行比较: enter image description here

Waveshare 图表明可以使用 CKP=1/CKE=0 或 CKP=0/CKE=1,您有:

SSP1STAT=0x00 ;
SSP1CON1=0x20 ;

哪个是 CKP=0/CKE=0(与您的逻辑分析仪轨迹相关)。

您需要:

SSP1STAT=0x20 ; // CKE=1
SSP1CON1=0x20 ; // CKP=0

SSP1STAT=0x00 ; // CKE=0
SSP1CON1=0x30 ; // CKP=1

由于 SCK 的空闲状态(由 CKP 控制)是无关紧要的,我建议保持原样并使用第一个建议 - 不知何故似乎更直观。

另请注意,您的逻辑分析仪还必须设置为相同的相位/极性时钟模式,才能正确显示数据。