打印
[活动专区]

【AT-START-F407测评】+LCD+FATFT+BMP图片显示

[复制链接]
1743|40
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
手头上有个驱动为HX8347的ardunio接口的LCD屏,今天我们就要ATF407来驱动它。屏幕用SPI方式驱动,同时SD卡也跟屏幕挂在同一路SPI上。
我们通过CS选择,分时使用这2个外设。并移植FATFS,让其显示SD卡里面的BMP图片。
废话不多说,我们先来配置SPI,这里使用SPI1,其中SPI的时钟速度不能太快,要考虑到SD卡的兼容性:
static void SPI1_GPIO_Configuration(void)
{
  GPIO_InitType GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(SPI1_GPIO_CLK|RCC_APB2PERIPH_SPI1|RCC_APB2PERIPH_AFIO, ENABLE);
       
         /* Configure SPI_FLASH pins*/
  GPIO_InitStructure.GPIO_Pins =  SPI1_PIN_MOSI;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(SPI1_GPIO, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pins = SPI1_PIN_MISO;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_10MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(SPI1_GPIO, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pins =  SPI1_PIN_SCK;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(SPI1_GPIO, &GPIO_InitStructure);
       
        //CS
  GPIO_InitStructure.GPIO_Pins = LCD_CS_PIN;
  GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_10MHz;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
  GPIO_Init(LCD_CS_GPIO, &GPIO_InitStructure);  
       
}

//SPI1 初始化
void SPI1_Init(void)
{

        SPI_InitType   SPI_InitStructure;
       
        /* Enable SPIy clock and GPIO clock for SPIy and SPIz */
  RCC_APB2PeriphClockCmd(SPI1_CLK , ENABLE);

  /* 1st phase: SPI1 Master */
  /* GPIO configuration ------------------------------------------------------*/
  SPI1_GPIO_Configuration();
       
        //CS 置高
        __LCD_CS_SET();
  
  /* SPI1 Config -------------------------------------------------------------*/
  SPI_DefaultInitParaConfig(&SPI_InitStructure);
  SPI_InitStructure.SPI_TransMode = SPI_TRANSMODE_FULLDUPLEX;
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2EDGE;
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_HIGH;
        SPI_InitStructure.SPI_CPOLY = 0;
        SPI_InitStructure.SPI_FirstBit = SPI_FIRSTBIT_MSB;
  SPI_InitStructure.SPI_FrameSize = SPI_FRAMESIZE_8BIT;
        SPI_InitStructure.SPI_MCLKP = SPI_MCLKP_8;
       
        //SPI_InitStructure.SPI_MCLKP = SPI_MCLKP_32;
       
       
  SPI_InitStructure.SPI_NSSSEL = SPI_NSSSEL_SOFT;
        SPI_InitStructure.SPI_Mode = SPI_MODE_MASTER;
  
  SPI_Init(SPI1, &SPI_InitStructure);

  
  /* Enable SPI1 */
  SPI_Enable(SPI1, ENABLE);

}
配置好了后,我们单独写一个SPI读写一个字节的函数:
unsigned int SPI1ReadWriteByte(unsigned char tx_data)
{
       
                /* Wait for SPIy Tx buffer empty */
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TE) == RESET);

    /* Send SPIy data */
    SPI_I2S_TxData(SPI1,tx_data);

    /* Wait for SPIy data reception */
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RNE) == RESET);
    /* Read SPIy received data */
    return SPI_I2S_RxData(SPI1);
       
}
我们定义LCD的读写,直接调用SPI1的读写函数:
#define __LCD_WRITE_BYTE(__DATA)  SPI1ReadWriteByte(__DATA)
其中LCD的其他几个控制引脚的配置,与JTAG的引脚有冲突,我们remap为SWD调试模式,释放PA15 PB3 PB4 3个引脚作为普通引脚
void lcd_port_init(void)
{

        GPIO_InitType GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOA| RCC_APB2PERIPH_GPIOC||RCC_APB2PERIPH_AFIO , ENABLE);
  //调试仅SWD
        GPIO_PinsRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//释放PA15  PB3  PB4
       
        GPIO_StructInit(&GPIO_InitStructure);
        //LCD-CS  PA15
        GPIO_InitStructure.GPIO_Pins = LCD_CS_PIN;                            
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
        GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
        GPIO_Init(LCD_CS_GPIO, &GPIO_InitStructure);
        //LCD-DC  PA8
        GPIO_InitStructure.GPIO_Pins = LCD_DC_PIN;                            
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
        GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
        GPIO_Init(LCD_DC_GPIO, &GPIO_InitStructure);
        //LCD-BKL PC7
        GPIO_InitStructure.GPIO_Pins = LCD_BKL_PIN;                           
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
        GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
        GPIO_Init(LCD_BKL_GPIO, &GPIO_InitStructure);

}
LCD其他操作函数:
void lcd_write_byte(uint8_t chByte, uint8_t chCmd)
{
    if (chCmd) {
        __LCD_DC_SET();
    } else {
        __LCD_DC_CLR();
    }
   
    __LCD_CS_CLR();
    __LCD_WRITE_BYTE(chByte);
    __LCD_CS_SET();
}

void lcd_write_word(uint16_t hwData)
{
    __LCD_DC_SET();
    __LCD_CS_CLR();
    __LCD_WRITE_BYTE(hwData >> 8);
    __LCD_WRITE_BYTE(hwData & 0xFF);
    __LCD_CS_SET();
}

void lcd_write_register(uint8_t chRegister, uint8_t chValue)
{
        lcd_write_byte(chRegister, LCD_CMD);
        lcd_write_byte(chValue, LCD_DATA);
}

//set the specified position of cursor on lcd.
//hwXpos specify x position
//hwYpos specify y position
void lcd_set_cursor(uint16_t hwXpos, uint16_t hwYpos)
{
        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
   
    lcd_write_register(0x02, hwXpos >> 8);
        lcd_write_register(0x03, hwXpos & 0xFF); //Column Start
        lcd_write_register(0x06, hwYpos >> 8);
        lcd_write_register(0x07, hwYpos & 0xFF); //Row Start
}

//clear the lcd with the specified color.
void lcd_clear_screen(uint16_t hwColor)  
{
        uint32_t i, wCount = LCD_WIDTH;
       
        wCount *= LCD_HEIGHT;
       
        lcd_set_cursor(0, 0);
        lcd_write_byte(0x22, LCD_CMD);
   
    __LCD_DC_SET();
        __LCD_CS_CLR();
        for (i = 0; i < wCount; i ++) {
                __LCD_WRITE_BYTE(hwColor >> 8);
                __LCD_WRITE_BYTE(hwColor & 0xFF);
        }
        __LCD_CS_SET();
}

//draw a point on the lcd with the specified color.
//hwXpos specify x position.
//hwYpos specify y position.
//hwColor color of the point.
void lcd_draw_point(uint16_t hwXpos, uint16_t hwYpos, uint16_t hwColor)
{
        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
        lcd_set_cursor(hwXpos, hwYpos);
        lcd_write_byte(0x22, LCD_CMD);
    lcd_write_word(hwColor);
}

//display a char at the specified position on lcd.
void lcd_display_char(uint16_t hwXpos, //specify x position.
                         uint16_t hwYpos, //specify y position.
                         uint8_t chChr,   //a char is display.
                         uint8_t chSize,  //specify the size of the char
                         uint16_t hwColor) //specify the color of the char
{             
        uint8_t i, j, chTemp;
        uint16_t hwYpos0 = hwYpos, hwColorVal = 0;

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }

                                          
    for (i = 0; i < chSize; i ++) {   
                if (FONT_1206 == chSize) {
                        chTemp = c_chFont1206[chChr - 0x20][i];  
                } else if (FONT_1608 == chSize) {
                        chTemp = c_chFont1608[chChr - 0x20][i];
                }
               
        for (j = 0; j < 8; j ++) {
                    if (chTemp & 0x80) {
                                hwColorVal = hwColor;
                                lcd_draw_point(hwXpos, hwYpos, hwColorVal);
                    }                       
                        chTemp <<= 1;
                        hwYpos ++;
                        if ((hwYpos - hwYpos0) == chSize) {
                                hwYpos = hwYpos0;
                                hwXpos ++;
                                break;
                        }
                }           
    }
}


//_pow
uint32_t _pow(uint8_t m, uint8_t n)
{
        uint32_t result = 1;
       
        while(n --) result *= m;   
        return result;
}

//display a number at the specified position on lcd.
void lcd_display_num(uint16_t hwXpos,  //specify x position.
                          uint16_t hwYpos, //specify y position.
                          uint32_t chNum,  //a number is display.
                          uint8_t chLen,   //length ot the number
                          uint8_t chSize,  //specify the size of the number
                          uint16_t hwColor) //specify the color of the number
{                
        uint8_t i;
        uint8_t chTemp, chShow = 0;

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
        for(i = 0; i < chLen; i ++) {
                chTemp = (chNum / _pow(10, chLen - i - 1)) % 10;
                if(chShow == 0 && i < (chLen - 1)) {
                        if(chTemp == 0) {
                                lcd_display_char(hwXpos + (chSize / 2) * i, hwYpos, ' ', chSize, hwColor);
                                continue;
                        } else {
                                chShow = 1;
                        }         
                }
                 lcd_display_char(hwXpos + (chSize / 2) * i, hwYpos, chTemp + '0', chSize, hwColor);
        }
}

//display a string at the specified position on lcd.
void lcd_display_string(uint16_t hwXpos, //specify x position.
                         uint16_t hwYpos,   //specify y position.
                         const uint8_t *pchString,  //a pointer to string
                         uint8_t chSize,    // the size of the string
                         uint16_t hwColor)  // specify the color of the string
{

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
    while (*pchString != '\0') {      
        if (hwXpos > (LCD_WIDTH - chSize / 2)) {
                        hwXpos = 0;
                        hwYpos += chSize;
                        if (hwYpos > (LCD_HEIGHT - chSize)) {
                                hwYpos = hwXpos = 0;
                                lcd_clear_screen(0x00);
                        }
                }
               
        lcd_display_char(hwXpos, hwYpos, (uint8_t)*pchString, chSize, hwColor);
        hwXpos += chSize / 2;
        pchString ++;
    }
}

//draw a line at the specified position on lcd.
void lcd_draw_line(uint16_t hwXpos0, //specify x0 position.
                      uint16_t hwYpos0, //specify y0 position.
                      uint16_t hwXpos1, //specify x1 position.
                      uint16_t hwYpos1, //specify y1 position.
                      uint16_t hwColor) //specify the color of the line
{
        int x = hwXpos1 - hwXpos0;
    int y = hwYpos1 - hwYpos0;
    int dx = abs(x), sx = hwXpos0 < hwXpos1 ? 1 : -1;
    int dy = -abs(y), sy = hwYpos0 < hwYpos1 ? 1 : -1;
    int err = dx + dy, e2;

        if (hwXpos0 >= LCD_WIDTH || hwYpos0 >= LCD_HEIGHT || hwXpos1 >= LCD_WIDTH || hwYpos1 >= LCD_HEIGHT) {
                return;
        }
   
    for (;;){
        lcd_draw_point(hwXpos0, hwYpos0 , hwColor);
        e2 = 2 * err;
        if (e2 >= dy) {     
            if (hwXpos0 == hwXpos1) break;
            err += dy; hwXpos0 += sx;
        }
        if (e2 <= dx) {
            if (hwYpos0 == hwYpos1) break;
            err += dx; hwYpos0 += sy;
        }
    }
}

//draw a circle at the specified position on lcd.
void lcd_draw_circle(uint16_t hwXpos,  //specify x position.
                        uint16_t hwYpos,  //specify y position.
                        uint16_t hwRadius, //specify the radius of the circle.
                        uint16_t hwColor)  //specify the color of the circle.
{
        int x = -hwRadius, y = 0, err = 2 - 2 * hwRadius, e2;

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
    do {
        lcd_draw_point(hwXpos - x, hwYpos + y, hwColor);
        lcd_draw_point(hwXpos + x, hwYpos + y, hwColor);
        lcd_draw_point(hwXpos + x, hwYpos - y, hwColor);
        lcd_draw_point(hwXpos - x, hwYpos - y, hwColor);
        e2 = err;
        if (e2 <= y) {
            err += ++ y * 2 + 1;
            if(-x == y && e2 <= x) e2 = 0;
        }
        if(e2 > x) err += ++ x * 2 + 1;
    } while(x <= 0);
}

//fill a rectangle out at the specified position on lcd.
void lcd_fill_rect(uint16_t hwXpos,  //specify x position.
                   uint16_t hwYpos,  //specify y position.
                   uint16_t hwWidth, //specify the width of the rectangle.
                   uint16_t hwHeight, //specify the height of the rectangle.
                   uint16_t hwColor)  //specify the color of rectangle.
{
        uint16_t i, j;

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
        for(i = 0; i < hwHeight; i ++){
                for(j = 0; j < hwWidth; j ++){
                        lcd_draw_point(hwXpos + j, hwYpos + i, hwColor);
                }
        }
}

//draw a vertical line at the specified position on lcd.
void lcd_draw_v_line(uint16_t hwXpos, //specify x position.
                        uint16_t hwYpos, //specify y position.
                        uint16_t hwHeight, //specify the height of the vertical line.
                        uint16_t hwColor)  //specify the color of the vertical line.
{       
        uint16_t i, y1 = MIN(hwYpos + hwHeight, LCD_HEIGHT - 1);

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
    for (i = hwYpos; i < y1; i ++) {
        lcd_draw_point(hwXpos, i, hwColor);
    }
}

//draw a horizonal line at the specified position on lcd.
void lcd_draw_h_line(uint16_t hwXpos, //specify x position.
                        uint16_t hwYpos,  //specify y position.
                        uint16_t hwWidth, //specify the width of the horizonal line.
                        uint16_t hwColor) //specify the color of the horizonal line.
{       
        uint16_t i, x1 = MIN(hwXpos + hwWidth, LCD_WIDTH - 1);

        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }
       
    for (i = hwXpos; i < x1; i ++) {
        lcd_draw_point(i, hwYpos, hwColor);
    }
}

void lcd_draw_rect(uint16_t hwXpos,  //specify x position.
                      uint16_t hwYpos,  //specify y position.
                      uint16_t hwWidth, //specify the width of the rectangle.
                      uint16_t hwHeight, //specify the height of the rectangle.
                      uint16_t hwColor)  //specify the color of rectangle.
{
        if (hwXpos >= LCD_WIDTH || hwYpos >= LCD_HEIGHT) {
                return;
        }

        lcd_draw_h_line(hwXpos, hwYpos, hwWidth, hwColor);
        lcd_draw_h_line(hwXpos, hwYpos + hwHeight, hwWidth, hwColor);
        lcd_draw_v_line(hwXpos, hwYpos, hwHeight, hwColor);
        lcd_draw_v_line(hwXpos + hwWidth, hwYpos, hwHeight + 1, hwColor);
}



//initialize the lcd.
//phwDevId pointer to device ID of lcd
void lcd_init(void)
{
//        __LCD_RST_CLR();
//        delay_ms(100);
//        __LCD_RST_SET();
        __LCD_CS_SET();
        __LCD_BKL_SET();

        //Driving ability Setting
        lcd_write_register(0xEA,0x00); //PTBA[15:8]
        lcd_write_register(0xEB,0x20); //PTBA[7:0]
        lcd_write_register(0xEC,0x0C); //STBA[15:8]
        lcd_write_register(0xED,0xC4); //STBA[7:0]
        lcd_write_register(0xE8,0x38); //OPON[7:0]
        lcd_write_register(0xE9,0x10); //OPON1[7:0]
        lcd_write_register(0xF1,0x01); //OTPS1B
        lcd_write_register(0xF2,0x10); //GEN
        //Gamma 2.2 Setting
        lcd_write_register(0x40,0x01); //
        lcd_write_register(0x41,0x00); //
        lcd_write_register(0x42,0x00); //
        lcd_write_register(0x43,0x10); //
        lcd_write_register(0x44,0x0E); //
        lcd_write_register(0x45,0x24); //
        lcd_write_register(0x46,0x04); //
        lcd_write_register(0x47,0x50); //
        lcd_write_register(0x48,0x02); //
        lcd_write_register(0x49,0x13); //
        lcd_write_register(0x4A,0x19); //
        lcd_write_register(0x4B,0x19); //
        lcd_write_register(0x4C,0x16); //
        lcd_write_register(0x50,0x1B); //
        lcd_write_register(0x51,0x31); //
        lcd_write_register(0x52,0x2F); //
        lcd_write_register(0x53,0x3F); //
        lcd_write_register(0x54,0x3F); //
        lcd_write_register(0x55,0x3E); //
        lcd_write_register(0x56,0x2F); //
        lcd_write_register(0x57,0x7B); //
        lcd_write_register(0x58,0x09); //
        lcd_write_register(0x59,0x06); //
        lcd_write_register(0x5A,0x06); //
        lcd_write_register(0x5B,0x0C); //
        lcd_write_register(0x5C,0x1D); //
        lcd_write_register(0x5D,0xCC); //
        //Power Voltage Setting
        lcd_write_register(0x1B,0x1B); //VRH=4.65V
        lcd_write_register(0x1A,0x01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)
        lcd_write_register(0x24,0x2F); //VMH(VCOM High voltage ~3.2V)
        lcd_write_register(0x25,0x57); //VML(VCOM Low voltage -1.2V)
        //****VCOM offset**///
        lcd_write_register(0x23,0x88); //for Flicker adjust //can reload from OTP
        //Power on Setting
        lcd_write_register(0x18,0x34); //I/P_RADJ,N/P_RADJ, Normal mode 60Hz
        lcd_write_register(0x19,0x01); //OSC_EN='1', start Osc
        lcd_write_register(0x01,0x00); //DP_STB='0', out deep sleep
        lcd_write_register(0x1F,0x88);// GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0
        delay_ms(5);
        lcd_write_register(0x1F,0x80);// GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0
        delay_ms(5);
        lcd_write_register(0x1F,0x90);// GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0
        delay_ms(5);
        lcd_write_register(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
        delay_ms(5);
        //262k/65k color selection
        lcd_write_register(0x17,0x05); //default 0x06 262k color // 0x05 65k color
        //SET PANEL
        lcd_write_register(0x36,0x00); //SS_P, GS_P,REV_P,BGR_P
        //Display ON Setting
        lcd_write_register(0x28,0x38); //GON=1, DTE=1, D=1000
        delay_ms(40);
        lcd_write_register(0x28,0x3F); //GON=1, DTE=1, D=1100

        lcd_write_register(0x16,0x18);
        //Set GRAM Area
        lcd_write_register(0x02,0x00);
        lcd_write_register(0x03,0x00); //Column Start
        lcd_write_register(0x04,0x00);
        lcd_write_register(0x05,0xEF); //Column End
        lcd_write_register(0x06,0x00);
        lcd_write_register(0x07,0x00); //Row Start
        lcd_write_register(0x08,0x01);
        lcd_write_register(0x09,0x3F); //Row End
   
  lcd_clear_screen(WHITE);
        //lcd_clear_screen(RED);
}
接下来,我们配置SD卡的驱动程序:
SD卡读写一样调用的SPI1的读写函数:
#define __SD_WRITE_BYTE(__DATA)  SPI1ReadWriteByte(__DATA)
SD开的CS端配置,其中触摸芯片XPT2046也挂在这个SPI上面,本例我们先不要,但是定义它的CS引脚,让它处于不选通状态:
void SD_port_init(void)
{
        GPIO_InitType GPIO_InitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOB, ENABLE);  
       
        GPIO_StructInit(&GPIO_InitStructure);
        //PB4  PB5
        GPIO_InitStructure.GPIO_Pins = SD_CS_PIN;                            
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
        GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pins = XPT2046_CS_PIN ;                            
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
        //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        __SD_CS_SET();
        __XPT2046_CS_SET();

}
SD其他操作函数:
//data: data to be written to sd card.
//return: data read from sd card.
uint8_t SD_SPI_ReadWriteByte(uint8_t data)
{
        return __SD_WRITE_BYTE(data);
}          

//set spi in low speed mode.
void SD_SPI_SpeedLow(void)
{
        SPI1->CTRL1&=0XFFC7;
        SPI1->CTRL1|=SPI_MCLKP_256;
        SPI_Enable(SPI1, ENABLE);

}


//set spi in high speed mode.
void SD_SPI_SpeedHigh(void)
{
        SPI1->CTRL1&=0XFFC7;
        SPI1->CTRL1|=SPI_MCLKP_32;
        SPI_Enable(SPI1, ENABLE);
}


//released spi bus
void SD_DisSelect(void)
{
        __SD_CS_SET();
        SD_SPI_ReadWriteByte(0xff);//providing extra 8 clocks  
}

//pick sd card and waiting until until it's ready
//return: 0: succed 1: failure
uint8_t SD_Select(void)
{
        __SD_CS_CLR();
        if(SD_WaitReady()==0)return 0;
        SD_DisSelect();
        return 1;
}

//waiting for sd card until it's ready
uint8_t SD_WaitReady(void)
{
        uint32_t t=0;
        do
        {
                if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;
                t++;                         
        }while(t<0XFFFFFF);
        return 1;
}

//waiting for response from sd card.
//Response: expect from sd card.
//return: succeed for 0, fail for other else
//return: 0 for success, other for failure.   
uint8_t SD_GetResponse(uint8_t Response)
{
        uint16_t Count=0xFFFF;                                                             
        while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;           
        if (Count==0)return MSD_RESPONSE_FAILURE;  
        else return MSD_RESPONSE_NO_ERROR;
}

//read a buffer from sd card.
//*buf: pointer to a buffer.
//len: length of the buffer.
//return: 0 for success, other for failure.   
uint8_t SD_RecvData(uint8_t*buf,uint16_t len)
{                                    
        if(SD_GetResponse(0xFE))return 1;//waiting for start command send back from sd card.
    while(len--)//receiving data...
    {
        *buf=__SD_WRITE_BYTE(0xFF);
        buf++;
    }

    //send 2 dummy write (dummy CRC)
    SD_SPI_ReadWriteByte(0xFF);
    SD_SPI_ReadWriteByte(0xFF);                                                                                                                      
    return 0;
}

//write a buffer containing 512 bytes to sd card.
//buf: data buffer
//cmd: command
//return: 0 for success, other for failure.   
uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd)
{       
        uint16_t t;                            
        if(SD_WaitReady())return 1;
        SD_SPI_ReadWriteByte(cmd);
        if(cmd!=0XFD)
        {
                for(t=0;t<512;t++)__SD_WRITE_BYTE(buf[t]);
            SD_SPI_ReadWriteByte(0xFF);//ignoring CRC
            SD_SPI_ReadWriteByte(0xFF);
                t=SD_SPI_ReadWriteByte(0xFF);
                if((t&0x1F)!=0x05)return 2;                                                                                                              
        }                                                                                                                                                                       
    return 0;
}


//send a command to sd card
//cmd:command
//arg: parameter
//crc: crc
//return: response sent back from sd card.
uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
{
    uint8_t r1;       
        uint8_t Retry=0;
        SD_DisSelect();
        if(SD_Select())return 0XFF;

    SD_SPI_ReadWriteByte(cmd | 0x40);
    SD_SPI_ReadWriteByte(arg >> 24);
    SD_SPI_ReadWriteByte(arg >> 16);
    SD_SPI_ReadWriteByte(arg >> 8);
    SD_SPI_ReadWriteByte(arg);          
    SD_SPI_ReadWriteByte(crc);
        if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff); //Skip a stuff byte when stop reading
        Retry=0X1F;
        do
        {
                r1=SD_SPI_ReadWriteByte(0xFF);
        }while((r1&0X80) && Retry--);         

    return r1;
}


//obtain CID including manufacturer informationfrom sd card  
//*cid_dat: pointer to the buffer storing CID, at least 16 bytes.
//return: 0 no error  1 error
uint8_t SD_GetCID(uint8_t *cid_data)
{
    uint8_t r1;          

    r1=SD_SendCmd(CMD10,0,0x01);
    if(r1==0x00)
        {
                r1=SD_RecvData(cid_data,16);         
    }
        SD_DisSelect();
        if(r1)return 1;
        else return 0;
}                                                                                                                                                                  

//obtain CSD including storage and speed.
//*csd_data : pointer to the buffer storing CSD, at least 16 bytes.
//return: 0 no error  1 error
uint8_t SD_GetCSD(uint8_t *csd_data)
{
    uint8_t r1;         
    r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD send CMD9 in order to get CSD
    if(r1==0)
        {
            r1=SD_RecvData(csd_data, 16);
    }
        SD_DisSelect();
        if(r1)return 1;
        else return 0;
}  

//obtian the totals of sectors of sd card.
//return: 0 error, other else for storage of sd card.
//numbers of bytes of each sector must be 512, otherwise fail to initialization.  
uint32_t SD_GetSectorCount(void)
{
    uint8_t csd[16];
    uint32_t Capacity;  
    uint8_t n;
        uint16_t csize;                                              
       
    if(SD_GetCSD(csd)!=0) return 0;            
    //calculation for SDHC below
    if((csd[0]&0xC0)==0x40)         //V2.00
    {       
                csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
                Capacity = (uint32_t)csize << 10;  //totals of sectors                   
    }else//V1.XX
    {       
                n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
                csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
                Capacity= (uint32_t)csize << (n - 9);
    }
    return Capacity;
}

//initialize sd card
uint8_t SD_Initialize(void)
{
    uint8_t r1;      
    uint16_t retry;  
    uint8_t buf[4];  
        uint16_t i;
   
    __SD_CS_SET();
        SD_SPI_SpeedLow();       
        for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);
        retry=20;
        do
        {
                r1=SD_SendCmd(CMD0,0,0x95);//enter to idle state
        }while((r1!=0X01) && retry--);
        SD_Type=0;
   
        if(r1==0X01)
        {
                if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
                {
                        for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp
                        if(buf[2]==0X01&&buf[3]==0XAA)//is it support of 2.7~3.6V
                        {
                                retry=0XFFFE;
                                do
                                {
                                        SD_SendCmd(CMD55,0,0X01);       
                                        r1=SD_SendCmd(CMD41,0x40000000,0X01);
                                }while(r1&&retry--);
                                if(retry&&SD_SendCmd(CMD58,0,0X01)==0) //start to identify the SD2.0 version of sd card.
                                {
                                        for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//get OCR
                                        if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //check CCS
                                        else SD_Type=SD_TYPE_V2;   
                                }
                        }
                }else//SD V1.x/ MMC        V3
                {
                        SD_SendCmd(CMD55,0,0X01);               
                        r1=SD_SendCmd(CMD41,0,0X01);       
                        if(r1<=1)
                        {               
                                SD_Type=SD_TYPE_V1;
                                retry=0XFFFE;
                                do //exit idle state
                                {
                                        SD_SendCmd(CMD55,0,0X01);       
                                        r1=SD_SendCmd(CMD41,0,0X01);
                                }while(r1&&retry--);
                        }else
                        {
                                SD_Type=SD_TYPE_MMC;//MMC V3
                                retry=0XFFFE;
                                do
                                {                                                                                            
                                        r1=SD_SendCmd(CMD1,0,0X01);
                                }while(r1&&retry--);  
                        }
                        if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;
                }
        }
        SD_DisSelect();
        SD_SPI_SpeedHigh();
        if(SD_Type)return 0;
        else if(r1)return r1;           
        return 0xaa;
}


//read SD card
//buf: data buffer
//sector: sector
//cnt: totals of sectors]
//return: 0 ok, other for failure
uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
        uint8_t r1;
        if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;
        if(cnt==1)
        {
                r1=SD_SendCmd(CMD17,sector,0X01);
                if(r1==0)
                {
                        r1=SD_RecvData(buf,512);   
                }
        }else
        {
                r1=SD_SendCmd(CMD18,sector,0X01);
                do
                {
                        r1=SD_RecvData(buf,512);
                        buf+=512;  
                }while(--cnt && r1==0);        
                SD_SendCmd(CMD12,0,0X01);       
        }   
        SD_DisSelect();
        return r1;//
}


//write sd card
//buf: data buffer
//sector: start sector
//cnt: totals of sectors]
//return: 0 ok, other for failure
uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
{
        uint8_t r1;
        if(SD_Type!=SD_TYPE_V2HC)sector *= 512;
        if(cnt==1)
        {
                r1=SD_SendCmd(CMD24,sector,0X01);
                if(r1==0)
                {
                        r1=SD_SendBlock(buf,0xFE);
                }
        }else
        {
                if(SD_Type!=SD_TYPE_MMC)
                {
                        SD_SendCmd(CMD55,0,0X01);       
                        SD_SendCmd(CMD23,cnt,0X01);       
                }
                r1=SD_SendCmd(CMD25,sector,0X01);
                if(r1==0)
                {
                        do
                        {
                                r1=SD_SendBlock(buf,0xFC);
                                buf+=512;  
                        }while(--cnt && r1==0);
                        r1=SD_SendBlock(0,0xFD);
                }
        }   
        SD_DisSelect();
        return r1;
}          
下面我们开始移植FATFS,这个主要就是diskio和ff的文件,这里也加载了FATFS常见操作的fatfs_storage文件。
主要修改的就是diskio文件,让我们本例程中的SD具体实现函数来替代FATFS里面的底层操作函数,当然也可在ff_config
头文件里面精简FATFS系统:
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */

#define SD_CARD         0  //SD卡,卷标为0

#define FLASH_SECTOR_SIZE         512                          

//初始化磁盘
DSTATUS disk_initialize (
        BYTE drv                                /* Physical drive nmuber (0..) */
)
{       
        uint8_t res=0;            
        switch(drv)
        {
                case SD_CARD://SD卡
                        res = SD_Initialize();//SD_Initialize()
                         if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
                        {
                                SD_SPI_SpeedLow();
                                SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
                                SD_SPI_SpeedHigh();
                        }
                          break;
                default:
                        res=1;
        }                 
        if(res)return  STA_NOINIT;
        else return 0; //初始化成功
}   
//获得磁盘状态
DSTATUS disk_status (
        BYTE drv                /* Physical drive nmuber (0..) */
)
{                  
    return 0;
}
//读扇区
//drv:磁盘编号0~9
//*buff:数据接收缓冲首地址
//sector:扇区地址
//count:需要读取的扇区数
DRESULT disk_read (
        BYTE drv,                /* Physical drive nmuber (0..) */
        BYTE *buff,                /* Data buffer to store read data */
        DWORD sector,        /* Sector address (LBA) */
        BYTE count                /* Number of sectors to read (1..255) */
)
{
        uint8_t res=0;
    if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误                          
        switch(drv)
        {
                case SD_CARD://SD卡
                        res=SD_ReadDisk(buff,sector,count);         
                         if(res)//STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常
                        {
                                SD_SPI_SpeedLow();
                                SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
                                SD_SPI_SpeedHigh();
                        }
                        break;
                default:
                        res=1;
        }
   //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    if(res==0x00)return RES_OK;         
    else return RES_ERROR;          
}  
//写扇区
//drv:磁盘编号0~9
//*buff:发送数据首地址
//sector:扇区地址
//count:需要写入的扇区数            
#if _READONLY == 0
DRESULT disk_write (
        BYTE drv,                        /* Physical drive nmuber (0..) */
        const BYTE *buff,                /* Data to be written */
        DWORD sector,                /* Sector address (LBA) */
        BYTE count                        /* Number of sectors to write (1..255) */
)
{
        uint8_t res=0;  
    if (!count)return RES_PARERR;//count不能等于0,否则返回参数错误                          
        switch(drv)
        {
                case SD_CARD://SD卡
                        res=SD_WriteDisk((uint8_t*)buff,sector,count);
                        break;
                default:
                        res=1;
        }
    //处理返回值,将SPI_SD_driver.c的返回值转成ff.c的返回值
    if(res == 0x00)return RES_OK;         
    else return RES_ERROR;                 
}
#endif /* _READONLY */

//其他表参数的获得
//drv:磁盘编号0~9
//ctrl:控制代码
//*buff:发送/接收缓冲区指针
DRESULT disk_ioctl (
        BYTE drv,                /* Physical drive nmuber (0..) */
        BYTE ctrl,                /* Control code */
        void *buff                /* Buffer to send/receive control data */
)
{       
        DRESULT res;                                                                               
        if(drv==SD_CARD)//SD卡
        {
            switch(ctrl)
            {
                    case CTRL_SYNC:
                                __SD_CS_CLR();
                        if(SD_WaitReady()==0)res = RES_OK;
                        else res = RES_ERROR;          
                                __SD_CS_SET();
                        break;         
                    case GET_SECTOR_SIZE:
                        *(WORD*)buff = 512;
                        res = RES_OK;
                        break;         
                    case GET_BLOCK_SIZE:
                        *(WORD*)buff = 8;
                        res = RES_OK;
                        break;         
                    case GET_SECTOR_COUNT:
                        *(DWORD*)buff = SD_GetSectorCount();
                        res = RES_OK;
                        break;
                    default:
                        res = RES_PARERR;
                        break;
            }
        }else res=RES_ERROR;//其他的不支持
    return res;
}

/*-----------------------------------------------------------------------*/
/* User defined function to give a current time to fatfs module          */
/* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */                                                                                                                                                                                                                                          
/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */                                                                                                                                                                                                                                                
DWORD get_fattime (void)
{
    return 0;
}
       
其他不予多说,在main文件里面添加2个函数,一个是SD挂载FATFS,一个是轮流显示SD卡根目录里面的BMP:
char* pDirectoryFiles[MAX_BMP_FILES];
FATFS microSDFatFs;
uint8_t str[20];

void SDCard_Config(void)
{
  uint32_t counter = 0;
  
  /* Check the mounted device */
  if(f_mount(µSDFatFs, (TCHAR const*)"/", 0) != FR_OK)
  {
      lcd_display_string(0, 16, "FATFS_NOT_MOUNTED", 16, RED);
  }  
  else
  {
    /* Initialize the Directory Files pointers (heap) */
    for (counter = 0; counter < MAX_BMP_FILES; counter++)
    {
      pDirectoryFiles[counter] = malloc(11);
    }
  }
}

static void Display_Images(void)
{   
    uint32_t bmplen = 0x00;
    uint32_t checkstatus = 0x00;
    uint32_t filesnumbers = 0x00;
    uint32_t bmpcounter = 0x00;
    DIR directory;
    FRESULT res;
   
    /* Open directory */
    res= f_opendir(&directory, "/");
    if((res != FR_OK))
    {
      if(res == FR_NO_FILESYSTEM)
      {
        /* Display message: SD card not FAT formated */
        lcd_display_string(0, 32, "SD_CARD_NOT_FORMATTED", 16, RED);  
         
      }
      else
      {
        /* Display message: Fail to open directory */
         lcd_display_string(0, 48, "SD_CARD_OPEN_FAIL", 16, RED);           
      }
    }
   
    /* Get number of bitmap files */
    filesnumbers = Storage_GetDirectoryBitmapFiles ("/", pDirectoryFiles);   
    /* Set bitmap counter to display first image */
    bmpcounter = 1;
   
    while (1)
    {     
        sprintf((char*)str, "%-11.11s", pDirectoryFiles[bmpcounter -1]);
        
        checkstatus = Storage_CheckBitmapFile((const char*)str, &bmplen);
        
        if(checkstatus == 0)
        {
          /* Format the string */
          Storage_OpenReadFile(0, 0, (const char*)str);
        }
        else if (checkstatus == 1)
        {
          /* Display message: SD card does not exist */
           lcd_display_string(0, 64, "SD_CARD_NOT_FOUND", 16, RED);  
        }
        else
        {
          /* Display message: File not supported */
            lcd_display_string(0, 80, "SD_CARD_FILE_NOT_SUPPORTED", 16, RED);
        }
        
        bmpcounter ++;
        if(bmpcounter > filesnumbers)
        {
          bmpcounter = 1;
        }
        
        delay_ms(1000);
//        delay_ms(1000);
//        delay_ms(1000);
    }
}
最终main里面添加:
int main(void)
{
        /*!< At this stage the microcontroller clock setting is already configured,
         this is done through SystemInit() function which is called from startup
         file (startup_at32f403_xx.s) before to branch to application main.
         To reconfigure the default setting of SystemInit() function, refer to
         system_at32f4xx.c file
        */     
         

  
  /* Config LED */
  AT32_Board_Init();
  /* SPIy Config -------------------------------------------------------------*/
  SPI1_Init();

        lcd_port_init();
        lcd_init();
       
        SD_port_init();
        SDCard_Config();
       
       
        lcd_draw_rect(30, 40, 150, 100, RED);
        lcd_draw_circle(120, 160, 50, BLUE);
        lcd_draw_line(30, 40, 180, 140, RED);

        lcd_draw_line(30, 220, 210, 240, RED);
        lcd_draw_line(30, 220, 120, 280, RED);
        lcd_draw_line(120, 280, 210, 240, RED);


        lcd_clear_screen(RED);
        Delay_ms(300);
        lcd_clear_screen(BLUE);
        Delay_ms(300);
        lcd_clear_screen(YELLOW);
        Delay_ms(300);
        lcd_clear_screen(BLACK);
        Delay_ms(300);
        lcd_clear_screen(GRAY);
        Delay_ms(300);
        lcd_clear_screen(GREEN);
        Delay_ms(300);
        lcd_clear_screen(WHITE);
        Delay_ms(300);

        lcd_display_string(60, 120, (const uint8_t *)"Hello, world !", FONT_1608, BLUE);
  lcd_display_string(30, 152, (const uint8_t *)"2.8' TFT Touch Shield", FONT_1608, RED);
        lcd_display_string(30, 152+32, (const uint8_t *)"T want fly high !", FONT_1608, GREEN);
  while (1)
  {
//                AT32_LEDn_Toggle(LED2);
//                AT32_LEDn_Toggle(LED3);
//                Delay_ms(300);       
                Display_Images();       
               
       
        }
}
编译,下载,查看:

代码(有需要的自取):
SPI_LCD _FATFS_BMP.rar (5.74 MB)


使用特权

评论回复
评论
muyichuan2012 2021-3-2 14:46 回复TA
分享的图片无法显示,可否重新上传一下呢? 
沙发
muyichuan2012| | 2021-3-2 13:07 | 只看该作者
感谢楼主分享,写的很详细。

使用特权

评论回复
板凳
qjp1988113|  楼主 | 2021-3-2 14:48 | 只看该作者
muyichuan2012 发表于 2021-3-2 13:07
感谢楼主分享,写的很详细。

你指什么图片?SD卡里面的BMP图片??

使用特权

评论回复
地板
muyichuan2012| | 2021-3-2 15:51 | 只看该作者
如图

使用特权

评论回复
5
qjp1988113|  楼主 | 2021-3-2 16:06 | 只看该作者
6
jinglixixi| | 2021-3-2 19:54 | 只看该作者

查了下记录,明白是什么了。

使用特权

评论回复
7
trucyw| | 2021-3-3 08:50 | 只看该作者
                             不错

使用特权

评论回复
8
单片小菜| | 2021-3-3 12:49 | 只看该作者
这个LCD驱动,还是比较实用的。

使用特权

评论回复
9
huangcunxiake| | 2021-3-3 13:16 | 只看该作者
驱动起来。看看。

使用特权

评论回复
10
goyhuan| | 2021-3-3 13:53 | 只看该作者
谢谢分享

使用特权

评论回复
11
里面有晴雨| | 2021-3-3 15:07 | 只看该作者
感谢楼主分享,看一下,确实不错的。

使用特权

评论回复
12
渔夫的烟斗| | 2021-3-4 23:02 | 只看该作者
有没有引脚连接方式的原理图?

使用特权

评论回复
13
zhouyong77| | 2021-3-5 08:14 | 只看该作者
谢谢楼主分享,看下资料。

使用特权

评论回复
14
qjp1988113|  楼主 | 2021-3-5 09:16 | 只看该作者
渔夫的烟斗 发表于 2021-3-4 23:02
有没有引脚连接方式的原理图?


使用特权

评论回复
15
便携手到老| | 2021-3-5 16:24 | 只看该作者
这个工程确实不错的,给楼主点个赞,比较好的应用哦。

使用特权

评论回复
16
usysm| | 2021-3-6 22:22 | 只看该作者
如何在LCD上使bmp图片以指定大小显示?

使用特权

评论回复
17
jkl21| | 2021-3-6 22:22 | 只看该作者
没有演示吗   

使用特权

评论回复
18
wwppd| | 2021-3-6 22:22 | 只看该作者
这个FATFS自己移植的吗   

使用特权

评论回复
19
maqianqu| | 2021-3-6 22:23 | 只看该作者
刷屏的速度怎么样   

使用特权

评论回复
20
dspmana| | 2021-3-6 22:26 | 只看该作者
移植一个ucgui吧   

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

627

帖子

2

粉丝