- 2024-10-17
-
加入了学习《DIY作品演示》,观看 【HC32F460开发板测评】06.模拟I2C实现OLED显示
- 2024-07-12
-
加入了学习《DIY作品演示》,观看 【GD32L233C-START评测】03.WS2812B驱动实现之PWM+DMA
-
加入了学习《DIY作品演示》,观看 【GD32L233C-START评测】04.WS2812B驱动实现之SPI
- 2024-05-10
-
回复了主题帖:
HC32F460,嘀嗒延时问题?
本帖最后由 xld0932 于 2024-5-10 09:34 编辑
1、官方的DDL_DelayMS函数是软件方式延时,根据当前配置的HCLK时钟频率进行计数,时间不算太精确
2、在官网可以下载当前的驱动库和样例,在HC32F460_DDL_Rev3.2.0\projects\ev_hc32f460_lqfp100_v2\examples\systick\systick_int有对应的示例程序,可参考例程实现你需要的SysTick延时函数功能
3、在你delay_init配置SysTick时,如果不需要用到中断的方式,就不要配置中断,配置了中断,就要实现中断函数
- 2024-03-26
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】07.熟悉板载VS1053B CODEC模块,通过I2S播放录音
1.概述
国民技术N32A455系列MCU支持3路SPI接口及2路I2S接口。SPI允许芯片与外部设备以半/全双工、同步、串行方式通信。此接口可以被配置成主模式,并为外部从设备提供通信时钟(SCK)。接口还能以多主配置方式工作。它可用于多种用途,包括使用一条双向数据线的双线单工同步传输,还可使用CRC校验的可靠通信。I2S也是一种3引脚的同步串行接口通讯协议, 2个标准的I2S接口(与SPI2和SPI3复用)可以工作于主或从模式,这2个接口可以配置为16位、 24位或32位传输,亦可配置为输入或输出通道,支持音频采样频率从8kHz到96kHz。它支持四种音频标准,包括飞利浦I2S标准, MSB和LSB对齐标准,以及PCM标准。
2.原理图
开发板选用CODEC芯片(VS1053B),输入LINE_IN接口J19以及驻极体MIC U16,一路耳机输出接口J21, 经过功放芯片(HT6872)输出一路外置喇叭接口SPK1&SPK2。 CODEC芯片位号U15,功放芯片(HT6872)位号U18。 CODEC支持SPI以及I2S两种通讯,若选用SPI通讯,则需连接跳线J46、 J47;若选用I2S通讯,则需连接跳线J37、 J38。
3.硬件环境
通过一个耳机连接到J21作为LINE_IN,通过咪头作为LINE_IN输入端口,根据说明,连接相应的跳线帽,如下所示:
4.录音、存储、播放
4.1.按键初始化及扫描
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] Initializes the peripherals used by the KEY driver.
*/
void KEY_Init(void)
{
GPIO_InitType GPIO_InitStructure;
/*!< KEY, KEY0-KEY1 , KEY3 Periph clock enable */
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOD | RCC_APB2_PERIPH_GPIOC, ENABLE);
GPIO_InitStructure.Pin = GPIO_PIN_12; //KEY0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitPeripheral(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_6|GPIO_PIN_7;//KEY1-KEY2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitPeripheral(GPIOC, &GPIO_InitStructure);
}
/**
* @brief scan key
*/
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t key_up = 1;
if(mode)key_up = 1;
if(key_up && (KEY0 == 0 || KEY1== 0 || KEY2== 0))
{
delay_ms(10);
key_up = 0;
if(KEY0 == 0)return KEY0_PRES;
else if(KEY1 == 0)return KEY1_PRES;
else if(KEY2 == 0)return KEY2_PRES;
}else if(KEY0 == 1 && KEY1 == 1 && KEY2 == 1)key_up = 1;
return 0;
}
4.2.SPI FLASH初始化配置
/**
* @brief Initializes the peripherals used by the SPI FLASH driver.
*/
void sFLASH_Init(void)
{
SPI_InitType SPI_InitStructure;
sFLASH_LowLevel_Init();
/*!< Deselect the FLASH: Chip Select high */
sFLASH_CS_HIGH();
/*!< SPI configuration */
SPI_InitStructure.DataDirection = SPI_DIR_DOUBLELINE_FULLDUPLEX;
SPI_InitStructure.SpiMode = SPI_MODE_MASTER;
SPI_InitStructure.DataLen = SPI_DATA_SIZE_8BITS;
SPI_InitStructure.CLKPOL = SPI_CLKPOL_HIGH;
SPI_InitStructure.CLKPHA = SPI_CLKPHA_SECOND_EDGE;
SPI_InitStructure.NSS = SPI_NSS_SOFT;
SPI_InitStructure.BaudRatePres = SPI_BR_PRESCALER_4;
SPI_InitStructure.FirstBit = SPI_FB_MSB;
SPI_InitStructure.CRCPoly = 7;
SPI_Init(sFLASH_SPI, &SPI_InitStructure);
/*!< Enable the sFLASH_SPI */
SPI_Enable(sFLASH_SPI, ENABLE);
}
4.3.VS1053复位及初始化
/**
* @brief vs1053b init
*/
void VS_Init(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_GPIOC, ENABLE);
GPIO_InitStructure.Pin = VS_DREQ_PIN; //PB11
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitPeripheral(VS_DREQ_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = VS_RST_PIN; //PB0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitPeripheral(VS_RST_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = VS_XCS_PIN;//PC2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitPeripheral(VS_XCS_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = VS_XDCS_PIN;//PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitPeripheral(VS_XDCS_PORT, &GPIO_InitStructure);
SPI3_Init();
}
/**
* @brief vs1053b soft reset
*/
void VS_Soft_Reset(void)
{
uint8_t retry=0;
while(VS_DQ==0); //wait soft reset finish
VS_SPI_ReadWriteByte(0Xff);
retry=0;
while(VS_RD_Reg(SPI_MODE)!=0x0800)
{
VS_WR_Cmd(SPI_MODE,0x0804); //soft reset
delay_ms(2);//wait at least 1.35ms
if(retry++>100)break;
}
while(VS_DQ==0);//wait soft reset finish
retry=0;
while(VS_RD_Reg(SPI_CLOCKF)!=0X9800)
{
VS_WR_Cmd(SPI_CLOCKF,0X9800);//set vs10xx clock
if(retry++>100)break;
}
delay_ms(20);
}
/**
* @brief vs1053b hardware reset
* [url=home.php?mod=space&uid=784970]@return[/url] 1:reset fail; 0:reset success
*/
uint8_t VS_HD_Reset(void)
{
uint16_t retry=0;
VS_RST = 0;
delay_ms(20);
VS_XDCS = 1;
VS_XCS = 1;
VS_RST = 1;
while(VS_DQ==0&&retry<200)//wait buf free
{
retry++;
delay_us(50);
};
delay_ms(20);
if(retry>=200)
{
return 1;
}
else
{
return 0;
}
}
4.4.固定频率音频测试
/**
* @brief vs1053b sine test
*/
void VS_Sine_Test(void)
{
VS_HD_Reset();
VS_WR_Cmd(SPI_VOL,0x5050); //set vol
VS_WR_Cmd(SPI_MODE,0x0820);//enter test mode
while(VS_DQ==0); //wait buf free
printf("mode sin:%x\r\n",VS_RD_Reg(SPI_MODE));
printf("sine freq=6000Hz\r\n");
//send sine test command:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
//n = 0x24, set VS10XX sine frequency
VS_SPI_SpeedLow();//set spi speed low
VS_XDCS=0;
VS_SPI_ReadWriteByte(0x53);
VS_SPI_ReadWriteByte(0xef);
VS_SPI_ReadWriteByte(0x6e);
VS_SPI_ReadWriteByte(0x30);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
delay_100ms(25);
VS_XDCS=1;
delay_ms(100);
//exit sine test
VS_XDCS=0;
VS_SPI_ReadWriteByte(0x45);
VS_SPI_ReadWriteByte(0x78);
VS_SPI_ReadWriteByte(0x69);
VS_SPI_ReadWriteByte(0x74);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
delay_ms(100);
VS_XDCS=1;
delay_ms(100);
VS_HD_Reset();
VS_WR_Cmd(SPI_VOL,0x5050); //set vol
VS_WR_Cmd(SPI_MODE,0x0820);//enter test mode
while(VS_DQ==0); //wait buf free
printf("mode sin:%x\r\n",VS_RD_Reg(SPI_MODE));
printf("sine freq=1000Hz\r\n");
//send sine test command:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
//n = 0x24, set VS10XX sine frequency
VS_SPI_SpeedLow();//set spi speed low
//send sine test command:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
//n = 0x44, set VS10XX sine frequency
VS_XDCS=0;
VS_SPI_ReadWriteByte(0x53);
VS_SPI_ReadWriteByte(0xef);
VS_SPI_ReadWriteByte(0x6e);
VS_SPI_ReadWriteByte(0x44);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
delay_100ms(25);
VS_XDCS=1;
delay_ms(100);
//exit sine test
VS_XDCS=0;
VS_SPI_ReadWriteByte(0x45);
VS_SPI_ReadWriteByte(0x78);
VS_SPI_ReadWriteByte(0x69);
VS_SPI_ReadWriteByte(0x74);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
VS_SPI_ReadWriteByte(0x00);
delay_ms(100);
VS_XDCS=1;
delay_ms(100);
}
4.5.按键功能实现
/**
* @brief recoder play
* @return play result
*/
uint8_t recoder_play(void)
{
uint8_t key;
uint8_t rval=0;
__WaveHeader *wavhead=0;
unsigned int sectorsize=0;
uint8_t *recbuf = {0};
uint16_t w;
uint16_t idx=0;
uint8_t rec_sta=0;//recoder state
//[7]:0,no recoder;1,exit recoder;
//[6:1]:reserve
//[0]:0,recoding;1,pause recode
uint8_t recagc=4; //default gain
uint8_t playFlag=0; //recoder play flag
wavhead=(__WaveHeader*)mymalloc(sizeof(__WaveHeader));
if(wavhead==NULL)rval=1;
recbuf=mymalloc(DATASIZE);
if(recbuf==NULL)rval=1;
if(rval==0)
{
while(VS_RD_Reg(SPI_HDAT1)>>8); //wait buf free
printf("Record test!");
while(rval==0)
{
key=KEY_Scan(0);
switch(key)
{
case KEY0_PRES: //REC/PAUSE
printf("key0:rec is down\r\n");
if(rec_sta&0X01)
{
rec_sta&=0XFE;//pausing, cancel pause
}
else if(rec_sta&0X80)//recording,pause
{
rec_sta|=0X01; //pause
}
else //no recording
{
printf("erase flash,please wait a moment\r\n");
erase_recoder_file_in_flash();
printf("start rec\r\n");
while(VS_HD_Reset());
VS_Soft_Reset();
recoder_enter_rec_mode(recagc*1024);
while((VS_RD_Reg(SPI_HDAT1)>>8));
rec_sta|=0X80; //start recode
recoder_wav_init(wavhead);//init WAV data
delay_ms(200);
}
break;
case KEY1_PRES: //STOP&SAVE
printf("key1:stop/save is down\r\n");
if(rec_sta&0X80)//exit record data
{
wavhead->riff.ChunkSize=sectorsize*DATASIZE+36; //all file size
wavhead->data.ChunkSize=sectorsize*DATASIZE; //data size
W25QXX_Write((uint8_t*)wavhead, RECORDERADDR-44, sizeof(__WaveHeader));//write WaveHeader data 44Byte
printf("save file in flash ok!all file size=%dkByte\r\n",(sectorsize*DATASIZE+44)/1024);
sectorsize=0;
}
rec_sta=0;
break;
case KEY2_PRES://play record
printf("wk_up:play is down\r\n");
if(rec_sta==0)
{
playFlag=1;
}
break;
}
//read data from vs1053b
if(rec_sta==0X80)
{
w=VS_RD_Reg(SPI_HDAT1); //get vs1053b buf exit data count
if((w>=256 && w<=896))
{
idx=0;
while(idx<DATASIZE)
{
w=VS_RD_Reg(SPI_HDAT0); //get data
recbuf[idx++]=w&0XFF;
recbuf[idx++]=w>>8;
}
if(sectorsize<1024*1024/DATASIZE)//recoder max size 1M
{
sFLASH_WriteBuffer(recbuf,RECORDERADDR+sectorsize*DATASIZE,DATASIZE);//write data to flash 512 byte
sectorsize++;
}
else
{
sectorsize=1024*1024/DATASIZE;
printf("err:flash is all,sectorsize=%d\r\n",sectorsize);
}
}
}
else
{
if(playFlag)
{
printf("play:\r\n");
rec_play_wav();
playFlag = 0;
while(VS_HD_Reset());
}
delay_ms(5);
}
}
}
myfree(wavhead);
myfree(recbuf);
return rval;
}
4.6.录音相关操作
/**
* @brief enter pcm recoder mode
*/
void recoder_enter_rec_mode(uint16_t agc)
{
while(VS_DQ==0);
VS_WR_Cmd(SPI_BASS,0x0000);
VS_WR_Cmd(SPI_AICTRL0,8000); //set sampling rate 8Khz
VS_WR_Cmd(SPI_AICTRL1,agc); //set agc:0,default gain.1024 equal to 1,512 equal to 0.5, max value 65535=64
VS_WR_Cmd(SPI_AICTRL2,0); //set gain max,0, 65536=64X
VS_WR_Cmd(SPI_AICTRL3,6); //MIC single left channel input PCM
VS_WR_Cmd(SPI_CLOCKF,0x2000); //set vs10xx clock,MULT:2 doube frequency;ADD:not allow;CLK:12.288Mhz
VS_WR_Cmd(SPI_MODE,0x1804); //MIC,recoder active
delay_ms(5); //wait at least 1.35ms
VS_Load_Patch((uint16_t*)wav_plugin,40);//VS1053 WAV recoder need patch
}
/**
* @brief recoder wav init
*/
void recoder_wav_init(__WaveHeader* wavhead)
{
wavhead->riff.ChunkID=0X46464952; //"RIFF"
wavhead->riff.ChunkSize=0; //size
wavhead->riff.Format=0X45564157; //"WAVE"
wavhead->fmt.ChunkID=0X20746D66; //"fmt "
wavhead->fmt.ChunkSize=16; //16bit
wavhead->fmt.AudioFormat=0X01; //0X01,PCM;0X01,IMA ADPCM
wavhead->fmt.NumOfChannels=1; //single channel
wavhead->fmt.SampleRate=8000; //8Khz sampling rate
wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*2;//16bit 2byte
wavhead->fmt.BlockAlign=2; //block size,1 block = 2byte
wavhead->fmt.BitsPerSample=16; //16 bit PCM
wavhead->data.ChunkID=0X61746164; //"data"
wavhead->data.ChunkSize=0; //data size
}
4.7.存储录音
uint8_t W25QXX_BUFFER[4096];
void W25QXX_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;
uint16_t i;
uint8_t * W25QXX_BUF;
W25QXX_BUF = W25QXX_BUFFER;
secpos = WriteAddr / 4096;
secoff = WriteAddr % 4096;
secremain = 4096 - secoff;
if(NumByteToWrite <= secremain)
{
secremain = NumByteToWrite;
}
while(1)
{
sFLASH_ReadBuffer(W25QXX_BUF, WriteAddr, secremain);
for(i = 0; i < secremain; i++)
{
if(W25QXX_BUF[i] != 0XFF)
break;//need erase first
}
if(i < secremain)
{
sFLASH_ReadBuffer(W25QXX_BUF, secpos * 4096, 4096); //read back a sector data
W25QXX_Erase_Sector(secpos); //erase the sector
for(i = 0; i < secremain; i++)
{
W25QXX_BUF[i + secoff] = pBuffer[i];
}
W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096);
}
else
{
W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain);
}
if(NumByteToWrite == secremain)
{
break;
}
else
{
secpos++;
secoff = 0;
pBuffer += secremain;
WriteAddr += secremain;
NumByteToWrite -= secremain;
if(NumByteToWrite > 4096)
{
secremain = 4096;
}
else
{
secremain = NumByteToWrite;
}
}
}
W25QXX_Wait_Busy();
}
4.8.播放录音
/**
* @brief play wav file
* @return play result
*/
uint8_t rec_play_wav()
{
uint8_t rval=0;
uint8_t *databuf;
uint16_t i=0;
unsigned int sectorsize=0,n=0;
uint16_t data_size = 512;
databuf = mymalloc(data_size);
if(databuf==NULL)rval=0XFF;//malloc memory fail
if(rval==0)
{
VS_HD_Reset(); //VS hardware reset
VS_Soft_Reset(); //VS software reset
VS_Set_Vol(220); //set the volume
VS_Reset_DecodeTime(); //reset decode time
//read back file size£¬file size-8
sFLASH_ReadBuffer(databuf,RECORDERADDR-44+4,4);
sectorsize+=databuf[3]<<24;
sectorsize+=databuf[2]<<16;
sectorsize+=databuf[1]<<8;
sectorsize+=databuf[0];
if(sectorsize == 0xFFFFFFFF)
{
printf("no recoder file\r\n");
return 1;
}
sectorsize+=8;//file size
VS_SPI_SpeedHigh();
while(1)
{
VS_XDCS = 1;
sFLASH_ReadBuffer(databuf,RECORDERADDR-44+n*data_size,data_size);
i=0;
do
{
if(VS_Send_MusicData(databuf+i)==0)
{
i+=32;//send music data to vs
}
}while(i<data_size);//send 512 byte
n++;
if(n%2 == 0)
{
printf("play=%d\r\n",n/2);
}
if(n==((sectorsize-44)/data_size)+1)
{
rval=0;
printf("the file size=%dkByte\r\n",sectorsize/1024);
break;
}
VS_XDCS = 0;
}
}
myfree(databuf);
return rval;
}
5.运行结果
程序启动后,先播放了3段不同频率的音频,然后通过按下S3按键开始录音,此时可以将嘴靠近MIC近一些进行说话,然后按下S4按键,将刚刚的录音保存到SPI FLASH中,最后可以通过按下S5按键来播放刚刚的录音,录音从耳机中播出
6.附件
- 2024-03-25
-
回复了主题帖:
【国民技术车规MCU N32A455开发板】06.熟悉SDIO接口,移植FatFs文件系统实现文件读写
有2个地方需要注意的是,在移植FatFs后,需要对调用的SD_ReadBlock和SD_WriteBlock做一下修改,就是将这个函数的如下判断语句给注释掉:
// if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)
// {
// BlockSize = 512;
// ReadAddr /= 512;
// }
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】06.熟悉SDIO接口,移植FatFs文件系统实现文件读写
本帖最后由 xld0932 于 2024-3-25 15:38 编辑
1.概述
国民N32A455系列MCU支持1路SDIO接口,安全数字输入输出接口(Secure Digital Input and Output),简称SDIO接口, SDIO主机接口为AHB外设总线和多媒体卡(MMC)、 SD存储卡、 SDIO卡设备间提供了操作接口。SDIO时钟速率可达48MHz。
2.原理图
3.SDIO示例程序
通过官方的示例程序“Nationstech.N32A455_Library.1.1.0\projects\n32a455_EVAL\examples\SDIO\uSDCard”,测试TF卡,通过示例程序读取TF卡数据,获取TF卡信息,运行结果如下所示:
4.移植FatFs文件系统
我们先将FatFs源文件解压并添加到工程中,然后配置头文件的包含路径:
然后我们对diskio.c接口文件进行移植,直接调试官方示例程序中的应用函数,需要注意的是官方示例程序默认是DMA方式,在操作缓存的时候需要注意哦,可以参考官方示例程序的写法,具体如下所示:
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include <stdio.h>
#include "sdio_sdcard.h"
#define diskio_BLOCK_SIZE 512
#pragma pack(4)
u32 diskio_Buffer_Block_Tx[diskio_BLOCK_SIZE / 4];
u32 diskio_Buffer_Block_Rx[diskio_BLOCK_SIZE / 4];
#pragma pack()
#define diskio_Buffer_Block_Tx ((uint8_t *)diskio_Buffer_Block_Tx)
#define diskio_Buffer_Block_Rx ((uint8_t *)diskio_Buffer_Block_Rx)
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
for (UINT i = 0; i < count; i++)
{
SD_ReadBlock(diskio_Buffer_Block_Rx, sector++, SDCardInfo.CardBlockSize);
SD_WaitReadOperation();
for (UINT j = 0; j < SDCardInfo.CardBlockSize; j++)
{
buff[i * 512 + j] = diskio_Buffer_Block_Rx[j];
}
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
for (UINT i = 0; i < count; i++)
{
for (UINT j = 0; j < SDCardInfo.CardBlockSize; j++)
{
diskio_Buffer_Block_Tx[j] = buff[i * 512 + j];
}
SD_WriteBlock(diskio_Buffer_Block_Tx, sector++, SDCardInfo.CardBlockSize);
SD_WaitWriteOperation();
}
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = RES_OK;
switch(cmd)
{
case CTRL_SYNC:
break;
case GET_SECTOR_COUNT:
*(WORD *)buff = SDCardInfo.CardCapacity / SDCardInfo.CardBlockSize;
break;
case GET_SECTOR_SIZE:
*(WORD *)buff = SDCardInfo.CardBlockSize;
break;
case GET_BLOCK_SIZE:
*(WORD *)buff = 1;
break;
default:
res = RES_PARERR;
break;
}
return res;
}
DWORD get_fattime(void)
{
DWORD ret_val = 0;
/* 2020-10-12 18:05:10 */
ret_val = (20 << 25)
+ (10 << 21)
+ (12 << 16)
+ (18 << 11)
+ (05 << 5)
+ (10 / 2);
return ret_val;
}
5.文件读写操作
在移植好FatFs文件系统后,我们就来编写一个文件系统的挂载、对文件的打开、关闭、读写这些基本操作的演示函数,如下所示:
#include <string.h>
#include "ff.h"
#include "diskio.h"
#include "ffconf.h"
void File_System_Initialize(void)
{
FATFS FatFs;
FIL File;
UINT br = 0, bw = 0;
FRESULT Result;
uint8_t Buffer[200];
memset(Buffer, 0, sizeof(Buffer));
Result = f_mount(&FatFs, "0:", 1);
if(Result)
{
printf("\r\nf_mount Fail! Result = %d\r\n", Result);
}
else
{
Result = f_open(&File, "0:/HELLO.TXT", FA_READ);
if(Result != RES_OK)
{
printf("\r\nf_open HELLO.txt Fail! Result = %d\r\n", Result);
}
else
{
do
{
Result = f_read(&File, Buffer, 200, &br);
if(br != 0) printf("\r\nf_read : %s\r\n", Buffer);
} while(br != 0);
f_close(&File);
}
Result = f_open(&File, "0:/TEST.TXT", FA_CREATE_ALWAYS | FA_WRITE);
if (Result != RES_OK)
{
printf("\r\nf_open TEST.txt Fail! Result = %d\r\n", Result);
}
else
{
Result = f_write(&File, "TEST...", 7, &bw);
if (Result != RES_OK)
{
printf("\r\nf_write TEST.txt Fail! Result = %d\r\n", Result);
}
else
{
printf("\r\nf_write TEST.txt Result = %d, bw = %d\r\n", Result, bw);
f_sync(&File);
}
f_close(&File);
}
}
}
6.运行结果
能够正确的读取到TF卡中文件的数据内容,以及创建新文件并写入相应内容,并返回正常的写入状态值,如下图所示:
7.附件
- 2024-03-16
-
回复了主题帖:
【国民技术车规MCU N32A455开发板】05、通过硬件I2C熟悉板载EEPROM的操作和应用
lugl4313820 发表于 2024-3-16 06:59
DMA的方式比普通的读取在快好多倍呀?
读写的速度是一样的呀,只是DMA可以释放MCU资源去做其它事情……
- 2024-03-15
-
回复了主题帖:
【国民技术车规MCU N32A455开发板】05、通过硬件I2C熟悉板载EEPROM的操作和应用
Jacktang 发表于 2024-3-15 07:25
国民技术N32A455系列MCU还是很强悍的
- 2024-03-14
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】05、通过硬件I2C熟悉板载EEPROM的操作和应用
1.概述
国民技术N32A455系列MCU搭载了多达4个独立的I2C总线接口,它提供多主机功能,控制所有I2C总线特定的时序、协议、仲裁和定时。支持多种通信速率模式(最高支持1MHz),支持DMA操作,同时与SMBus 2.0兼容。 I2C模块有多种用途,包括CRC码的生成和校验、 SMBus(系统管理总线—System Management Bus)和PMBus(电源管理总线—PowerManagement Bus)。
2.N32A455开发板EEPROM原理图
开发板选用EEROM芯片(CAT24C08YI-GT3),分别连接到硬件I2C1的PB8和PB9这两个引脚上,EEPROM的A0~A2地址选择引脚都连接了GND,如下所示:
3.I2C示例程序
通过I2C模块与外部EEPRON的通信,对EEPROM进行读取操作,熟悉I2C的编程和应用方法:
int main(void)
{
uint16_t i = 0;
log_init();
log_info("this is a I2C EEPROM demo\r\n");
/* Initialize the I2C EEPROM driver ----------------------------------------*/
I2C_EE_Init();
/* Fill the buffer to send */
for (i = 0; i < TEST_EEPROM_SIZE; i++)
{
tx_buf[i] = i;
}
log_info("\r\nWrite to I2C EEPROM...");
/* First write in the memory followed by a read of the written data --------*/
/* Write to I2C EEPROM from TEST_EEPROM_ADDR */
I2C_EE_WriteBuffer(tx_buf, TEST_EEPROM_ADDR, TEST_EEPROM_SIZE);
log_info("\r\nRead from I2C EEPROM :");
/* Read from I2C EEPROM from sEE_READ_ADDRESS1 */
I2C_EE_ReadBuffer(rx_buf, TEST_EEPROM_ADDR, TEST_EEPROM_SIZE);
for (i = 0; i < TEST_EEPROM_SIZE; i++)
{
if ((i % 16) == 0)
{
printf("\r\n");
}
printf("0x%02X ", rx_buf[i]);
}
printf("\r\n");
/* Check if the data written to the memory is read correctly */
test_status = Buffercmp(tx_buf, rx_buf, TEST_EEPROM_SIZE);
if (test_status == PASSED)
{
log_info("\r\nthe write and read data are the same,I2C EEPROM test pass\r\n");
}
else
{
log_info("\r\nthe write and read data are different,I2C EEPROM test fail\r\n");
}
while (1)
{
}
}
EEPROM写PAGE操作:
写PAGE操作实现了查访和DMA两种方式,操作流程都相同,都是先产生START信号、发送器件地址、发送写入地址、写入数据、最后发送STOP停止位;每一个步骤都对应一个事件检测,判断是否操作完成:
void I2C_EE_PageWrite(u8* pBuffer, u16 WriteAddr, u16 NumByteToWrite)
{
#if PROCESS_MODE == 0 /* polling */
sEETimeout = sEE_LONG_TIMEOUT;
while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send START condition */
I2C_GenerateStart(I2Cx, ENABLE);
/** Test on EV5 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send EEPROM address for write */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_SEND);
/** Test on EV6 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send the EEPROM's internal address to write to */
I2C_SendData(I2Cx, WriteAddr);
/** Test on EV8 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** While there is data to be written */
while (NumByteToWrite--)
{
/** Send the current byte */
I2C_SendData(I2Cx, *pBuffer);
/** Point to the next byte to be written */
pBuffer++;
/** Test on EV8 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
}
/** Send STOP condition */
I2C_GenerateStop(I2Cx, ENABLE);
I2C_EE_WaitEepromStandbyState();
I2C_EE_WriteOnePageCompleted();
#elif PROCESS_MODE == 1 /* interrupt */
/** initialize static parameter */
MasterDirection = Transmitter;
i2c_comm_state = COMM_PRE;
/** initialize static parameter according to input parameter */
SlaveADDR = EEPROM_ADDRESS; /// this byte shoule be send by F/W (in loop or INTSTS way)
DeviceOffset = WriteAddr; /// this byte can be send by both F/W and DMA
OffsetDone = FALSE;
memcpy(SendBuf, pBuffer, NumByteToWrite);
BufCount = 0;
Int_NumByteToWrite = NumByteToWrite;
I2C_ConfigAck(I2C1, ENABLE);
I2C_ConfigInt(I2C1, I2C_INT_EVENT | I2C_INT_BUF | I2C_INT_ERR, ENABLE);
/** Send START condition */
sEETimeout = sEE_LONG_TIMEOUT;
while (I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
I2C_GenerateStart(I2C1, ENABLE);
I2C_EE_WaitOperationIsCompleted();
I2C_EE_WriteOnePageCompleted();
#elif PROCESS_MODE == 2 /* DMA */
DMA_InitType DMA_InitStructure;
/** DMA initialization */
DMA_DeInit(DMA1_CH6);
DMA_InitStructure.PeriphAddr = (u32)&I2Cx->DAT; /// (u32)I2C1_DR_Address;
DMA_InitStructure.MemAddr = (u32)pBuffer; /// from function input parameter
DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST; /// fixed for send function
DMA_InitStructure.BufSize = NumByteToWrite; /// from function input parameter
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; // fixed
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; /// fixed
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE; /// fixed
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte; /// fixed
DMA_InitStructure.CircularMode = DMA_MODE_NORMAL; /// fixed
DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH; /// up to user
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; /// fixed
DMA_Init(DMA1_CH6, &DMA_InitStructure);
sEETimeout = sEE_LONG_TIMEOUT;
while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send START condition */
I2C_GenerateStart(I2Cx, ENABLE);
/** Test on EV5 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send EEPROM address for write */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_SEND);
/** Test on EV6 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send the EEPROM's internal address to write to */
I2C_SendData(I2Cx, WriteAddr);
/** Test on EV8 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDING))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
DMA_EnableChannel(DMA1_CH6, ENABLE);
I2C_EnableDMA(I2C1, ENABLE);
sEETimeout = sEE_LONG_TIMEOUT;
while(I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send STOP condition */
I2C_GenerateStop(I2Cx, ENABLE);
I2C_EnableDMA(I2Cx, DISABLE);
DMA_EnableChannel(DMA1_CH6, DISABLE);
I2C_EE_WaitEepromStandbyState();
I2C_EE_WriteOnePageCompleted();
#endif
}
EEPROM读取数据:
EEPROM数据读取的函数,依然使用了查询和DMA两种实现方式,EEPROM的读取大小没有写入PAGE字节数的限制了;具体的操作流程:产生START信号、发送器件地址、发送读取地址、产生RESTART信号、发送读取命令、读取数据:
void I2C_EE_ReadBuffer(u8* pBuffer, u16 ReadAddr, u16 NumByteToRead)
{
#if PROCESS_MODE == 0 /* polling */
sEETimeout = sEE_LONG_TIMEOUT;
while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
I2C_ConfigNackLocation(I2Cx, I2C_NACK_POS_CURRENT); // clear ACKPOS
I2C_ConfigAck(I2Cx, ENABLE);
/** Send START condition */
I2C_GenerateStart(I2Cx, ENABLE);
/** Test on EV5 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send EEPROM address for write */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_SEND);
/** Test on EV6 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Clear EV6 by setting again the PE bit */
I2C_Enable(I2Cx, ENABLE);
/** Send the EEPROM's internal address to write to */
I2C_SendData(I2Cx, ReadAddr);
/** Test on EV8 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send STRAT condition a second time */
I2C_GenerateStart(I2Cx, ENABLE);
/** Test on EV5 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send EEPROM address for read */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_RECV);
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_ADDRF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** While there is data to be read */
if (NumByteToRead == 1)
{
/** Disable Acknowledgement */
I2C_ConfigAck(I2Cx, DISABLE);
(void)(I2Cx->STS1); /// clear ADDR
(void)(I2Cx->STS2);
I2C_GenerateStop(I2Cx, ENABLE);
}
else if (NumByteToRead == 2)
{
I2C_ConfigNackLocation(I2Cx, I2C_NACK_POS_NEXT); // set ACKPOS
(void)(I2Cx->STS1);
(void)(I2Cx->STS2);
I2C_ConfigAck(I2Cx, DISABLE);
}
else
{
I2C_ConfigAck(I2Cx, ENABLE);
(void)(I2Cx->STS1);
(void)(I2Cx->STS2);
}
while (NumByteToRead)
{
if (NumByteToRead <= 3)
{
/** One byte */
if (NumByteToRead == 1)
{
/** Wait until RXNE flag is set */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_RXDATNE))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Read data from DAT */
/** Read a byte from the EEPROM */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
}
/** Two bytes */
else if (NumByteToRead == 2)
{
/** Wait until BTF flag is set */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send STOP Condition */
I2C_GenerateStop(I2Cx, ENABLE);
/** Read data from DAT */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
/** Read data from DAT */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
}
/** 3 Last bytes */
else
{
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Disable Acknowledgement */
I2C_ConfigAck(I2Cx, DISABLE);
/** Read data from DAT */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
/** Wait until BTF flag is set */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send STOP Condition */
I2C_GenerateStop(I2Cx, ENABLE);
/** Read data from DAT */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
/** Read data from DAT */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
}
}
else
{
/** Test on EV7 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_RECVD_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Read a byte from the EEPROM */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
if (I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
/** Read a byte from the EEPROM */
*pBuffer = I2C_RecvData(I2Cx);
/** Point to the next location where the byte read will be saved */
pBuffer++;
/** Decrement the read bytes counter */
NumByteToRead--;
}
}
}
#elif PROCESS_MODE == 1 /* interrupt */
I2C_pBuffer = pBuffer;
MasterDirection = Receiver;
/** initialize static parameter according to input parameter*/
SlaveADDR = EEPROM_ADDRESS;
DeviceOffset = ReadAddr;
OffsetDone = FALSE;
i2c_comm_state = COMM_PRE;
I2C_ConfigNackLocation(I2Cx, I2C_NACK_POS_CURRENT); // clear ACKPOS
I2C_ConfigAck(I2C1, ENABLE);
I2C_ConfigInt(I2C1, I2C_INT_EVENT | I2C_INT_BUF | I2C_INT_ERR, ENABLE);
Int_NumByteToRead = NumByteToRead;
sEETimeout = sEE_LONG_TIMEOUT;
while (I2C_GetFlag(I2Cx, I2C_FLAG_BYTEF))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
I2C_GenerateStart(I2C1, ENABLE);
I2C_EE_WaitOperationIsCompleted();
#elif PROCESS_MODE == 2 /* DMA */
/** DMA initialization */
if(NumByteToRead > 1)
{
DMA_InitType DMA_InitStructure;
/** DMA initialization */
DMA_DeInit(DMA1_CH7);
DMA_InitStructure.PeriphAddr = (u32)&I2Cx->DAT; /// (u32)I2C1_DR_Address;
DMA_InitStructure.MemAddr = (u32)pBuffer; /// from function input parameter
DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC; /// fixed for read function
DMA_InitStructure.BufSize = NumByteToRead; /// from function input parameter
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE; /// fixed
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE; /// fixed
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE; /// fixed
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte; /// fixed
DMA_InitStructure.CircularMode = DMA_MODE_NORMAL; /// fixed
DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH; /// up to user
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE; /// fixed
DMA_Init(DMA1_CH7, &DMA_InitStructure);
}
while (I2C_GetFlag(I2Cx, I2C_FLAG_BUSY))
{
if ((sEETimeout--) == 0)
{
sEE_TIMEOUT_UserCallback();
}
}
/** Send START condition */
I2C_GenerateStart(I2Cx, ENABLE);
/** Test on EV5 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send EEPROM address for write */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_SEND);
/** Test on EV6 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_TXMODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Clear EV6 by setting again the PE bit */
I2C_Enable(I2Cx, ENABLE);
/** Send the EEPROM's internal address to write to */
I2C_SendData(I2Cx, ReadAddr);
/** Test on EV8 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_DATA_SENDED))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send STRAT condition a second time */
I2C_GenerateStart(I2Cx, ENABLE);
/** Test on EV5 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVT_MASTER_MODE_FLAG))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Send EEPROM address for read */
I2C_SendAddr7bit(I2Cx, EEPROM_ADDRESS, I2C_DIRECTION_RECV);
/* Test on EV6 and clear it */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_ADDRF)) //EV6
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** While there is data to be read */
if (NumByteToRead == 1)
{
/** Disable Acknowledgement */
I2C_ConfigAck(I2Cx, DISABLE);
(void)(I2Cx->STS1); /// clear ADDR
(void)(I2Cx->STS2);
I2C_GenerateStop(I2Cx, ENABLE);
/** Wait until RXNE flag is set */
sEETimeout = sEE_LONG_TIMEOUT;
while (!I2C_GetFlag(I2Cx, I2C_FLAG_RXDATNE))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
/** Read data from DAT */
/** Read a byte from the EEPROM */
*pBuffer = I2C_RecvData(I2Cx);
}
else
{
I2C_ConfigAck(I2Cx, ENABLE);
(void)(I2Cx->STS1);
(void)(I2Cx->STS2);
I2C_EnableDmaLastSend(I2Cx, ENABLE);
DMA_EnableChannel(DMA1_CH7, ENABLE);
I2C_EnableDMA(I2Cx, ENABLE);
sEETimeout = sEE_LONG_TIMEOUT;
while(!(DMA_GetFlagStatus(DMA1_FLAG_TC7,DMA1)))
{
if ((sEETimeout--) == 0)
sEE_TIMEOUT_UserCallback();
}
I2C_EnableDMA(I2Cx, DISABLE);
DMA_EnableChannel(DMA1_CH7, DISABLE);
I2C_EnableDmaLastSend(I2Cx, DISABLE);
I2C_GenerateStop(I2Cx, ENABLE);
}
I2C_EE_WaitOperationIsCompleted();
#endif
}
4.运行结果
5.工程源码
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】04、通过SPI FLASH熟悉SPI通讯(SPI1 & SPI2)
本帖最后由 xld0932 于 2024-3-14 15:26 编辑
1.概述
国民技术N32A455系列MCU搭载了3路SPI接口,同时还具备I2S功能;SPI允许芯片与外部设备以半/全双工、同步、串行方式通信。此接口可以被配置成主模式,并为外部从设备提供通信时钟(SCK)。接口还能以多主配置方式工作。它可用于多种用途,包括使用一条双向数据线的双线单工同步传输,还可使用CRC校验的可靠通信。
2.N32A455开发板SPI FLASH原理图
开发板板载一路SPI FLASH(W25Q128JVSIQTR),占用了SPI1外设资源,通过设置跳线J29、 J30、 J31、 J32与MCU的PA4、PA5、PA6、PA7相连接,所以在做SPI FLASH实验时,需要注意跳线的连接状态
3.SPI示例程序
我们参考官方的SPI FLASH示例工程,通过SPI1接口对SPI FLASH进行读、写、擦除等操作,通过修改代码将每个过程的数据打印出来,更加的直观:
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_n32a455.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_n32a455.c file
*/
log_init();
LedInit(GPIOE, LED1 | LED2);
LedOff(GPIOE, LED1 | LED2);
/* Initialize the SPI FLASH driver */
sFLASH_Init();
/* Get SPI Flash ID */
FlashID = sFLASH_ReadID();
printf("\r\nRead ID=0x%06x",FlashID);
/* Check the SPI Flash ID */
if ((FlashID == sFLASH_ID)||(FlashID == sFLASH_W25Q128_ID_DTR))
{
/* OK: Turn on LED1 */
LedOn(GPIOE, LED1);
/* Perform a write in the Flash followed by a read of the written data */
/* Erase SPI FLASH Sector to write on */
sFLASH_EraseSector(FLASH_SectorToErase);
/* Read data from SPI FLASH memory */
sFLASH_ReadBuffer(Rx_Buffer, FLASH_ReadAddress, BufferSize);
printf("\r\nRead after Erase...");
for (uint32_t i = 0; i < BufferSize; i++)
{
if ((i % 16) == 0)
{
printf("\r\n");
}
printf("0x%02X ", Rx_Buffer[i]);
}
printf("\r\n");
/* Write Tx_Buffer data to SPI FLASH memory */
sFLASH_WriteBuffer(Tx_Buffer, FLASH_WriteAddress, BufferSize);
/* Read data from SPI FLASH memory */
sFLASH_ReadBuffer(Rx_Buffer, FLASH_ReadAddress, BufferSize);
printf("\r\nRead after Write...");
for (uint32_t i = 0; i < BufferSize; i++)
{
if ((i % 16) == 0)
{
printf("\r\n");
}
printf("0x%02X ", Rx_Buffer[i]);
}
printf("\r\n");
printf("\r\n%s", Rx_Buffer);
printf("\r\n");
/* Check the correctness of written dada */
TransferStatus1 = Buffercmp(Tx_Buffer, Rx_Buffer, BufferSize);
if(PASSED == TransferStatus1)
printf("\r\nFlash write OK.");
else
printf("\r\nFlash write fail.");
/* TransferStatus1 = PASSED, if the transmitted and received data by SPI1
are the same */
/* TransferStatus1 = FAILED, if the transmitted and received data by SPI1
are different */
/* Perform an erase in the Flash followed by a read of the written data */
/* Erase SPI FLASH Sector to write on */
sFLASH_EraseSector(FLASH_SectorToErase);
/* Read data from SPI FLASH memory */
sFLASH_ReadBuffer(Rx_Buffer, FLASH_ReadAddress, BufferSize);
printf("\r\nRead after Erase...");
for (uint32_t i = 0; i < BufferSize; i++)
{
if ((i % 16) == 0)
{
printf("\r\n");
}
printf("0x%02X ", Rx_Buffer[i]);
}
printf("\r\n");
/* Check the correctness of erasing operation dada */
for (Index = 0; Index < BufferSize; Index++)
{
if (Rx_Buffer[Index] != 0xFF)
{
TransferStatus2 = FAILED;
break;
}
}
if(PASSED == TransferStatus2)
printf("\r\nSector erase OK.");
else
printf("\r\nSector erase fail.");
/* TransferStatus2 = PASSED, if the specified sector part is erased */
/* TransferStatus2 = FAILED, if the specified sector part is not well erased */
}
else
{
/* Error: Turn on LED2 */
LedOn(GPIOE, LED2);
printf("\r\nRead ID fail.");
}
while (1)
{
}
}
4.运行结果
4.1.硬件环境
4.2.运行结果
5.使用SPI2操作SPI FLASH的注意事项
N32A455开发板上的PE10\PE11\PE12\PE13这几个接口作为SPI2通讯接口,正好也没有被其它板载资源所占用,所以就使用这4个引脚来验证一下SPI2操作SPI FLASH的功能,首先需要对程序进行配置
5.1.在spi_flash.h文件中对操作SPI FLASH的接口和外设进行定义:
#if 0
#define sFLASH_SPI SPI1
#define sFLASH_SPI_CLK RCC_APB2_PERIPH_SPI1
#define sFLASH_SPI_SCK_PIN GPIO_PIN_5 /* PA.05 */
#define sFLASH_SPI_SCK_GPIO_PORT GPIOA /* GPIOA */
#define sFLASH_SPI_SCK_GPIO_CLK RCC_APB2_PERIPH_GPIOA
#define sFLASH_SPI_MISO_PIN GPIO_PIN_6 /* PA.06 */
#define sFLASH_SPI_MISO_GPIO_PORT GPIOA /* GPIOA */
#define sFLASH_SPI_MISO_GPIO_CLK RCC_APB2_PERIPH_GPIOA
#define sFLASH_SPI_MOSI_PIN GPIO_PIN_7 /* PA.07 */
#define sFLASH_SPI_MOSI_GPIO_PORT GPIOA /* GPIOA */
#define sFLASH_SPI_MOSI_GPIO_CLK RCC_APB2_PERIPH_GPIOA
#define sFLASH_CS_PIN GPIO_PIN_4 /* PA.04 */
#define sFLASH_CS_GPIO_PORT GPIOA /* GPIOA */
#define sFLASH_CS_GPIO_CLK RCC_APB2_PERIPH_GPIOA
#else
#define sFLASH_SPI SPI2
#define sFLASH_SPI_CLK RCC_APB1_PERIPH_SPI2
#define sFLASH_SPI_SCK_PIN GPIO_PIN_11/* PE.11 */
#define sFLASH_SPI_SCK_GPIO_PORT GPIOE /* GPIOE */
#define sFLASH_SPI_SCK_GPIO_CLK RCC_APB2_PERIPH_GPIOE
#define sFLASH_SPI_MISO_PIN GPIO_PIN_12/* PA.12 */
#define sFLASH_SPI_MISO_GPIO_PORT GPIOE /* GPIOE */
#define sFLASH_SPI_MISO_GPIO_CLK RCC_APB2_PERIPH_GPIOE
#define sFLASH_SPI_MOSI_PIN GPIO_PIN_13/* PA.13 */
#define sFLASH_SPI_MOSI_GPIO_PORT GPIOE /* GPIOE */
#define sFLASH_SPI_MOSI_GPIO_CLK RCC_APB2_PERIPH_GPIOE
#define sFLASH_CS_PIN GPIO_PIN_10/* PE.10 */
#define sFLASH_CS_GPIO_PORT GPIOE /* GPIOE */
#define sFLASH_CS_GPIO_CLK RCC_APB2_PERIPH_GPIOE
#endif
5.2.因为SPI1与SPI2这两个外设接口不在同一个总线上,所以需要对官方例程中出现外设时钟配置的地方进行修改,修改spi_flash.c文件中的函数,如下所示:
void sFLASH_LowLevel_DeInit(void)
{
GPIO_InitType GPIO_InitStructure;
/*!< Disable the sFLASH_SPI */
SPI_Enable(sFLASH_SPI, DISABLE);
/*!< DeInitializes the sFLASH_SPI */
SPI_I2S_DeInit(sFLASH_SPI);
/*!< sFLASH_SPI Periph clock disable */
if (sFLASH_SPI_CLK == RCC_APB2_PERIPH_SPI1)
{
RCC_EnableAPB2PeriphClk(sFLASH_SPI_CLK, DISABLE);
}
else
{
RCC_EnableAPB1PeriphClk(sFLASH_SPI_CLK, DISABLE);
}
/*!< Configure sFLASH_SPI pins: SCK */
GPIO_InitStructure.Pin = sFLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitPeripheral(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_SPI pins: MISO */
GPIO_InitStructure.Pin = sFLASH_SPI_MISO_PIN;
GPIO_InitPeripheral(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_SPI pins: MOSI */
GPIO_InitStructure.Pin = sFLASH_SPI_MOSI_PIN;
GPIO_InitPeripheral(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_CS_PIN pin: sFLASH Card CS pin */
GPIO_InitStructure.Pin = sFLASH_CS_PIN;
GPIO_InitPeripheral(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);
}
void sFLASH_LowLevel_Init(void)
{
GPIO_InitType GPIO_InitStructure;
/*!< sFLASH_SPI_CS_GPIO, sFLASH_SPI_MOSI_GPIO, sFLASH_SPI_MISO_GPIO
and sFLASH_SPI_SCK_GPIO Periph clock enable */
RCC_EnableAPB2PeriphClk(
sFLASH_CS_GPIO_CLK | sFLASH_SPI_MOSI_GPIO_CLK | sFLASH_SPI_MISO_GPIO_CLK | sFLASH_SPI_SCK_GPIO_CLK, ENABLE);
/*!< sFLASH_SPI Periph clock enable */
if (sFLASH_SPI_CLK == RCC_APB2_PERIPH_SPI1)
{
RCC_EnableAPB2PeriphClk(sFLASH_SPI_CLK, ENABLE);
}
else
{
RCC_EnableAPB1PeriphClk(sFLASH_SPI_CLK, ENABLE);
GPIO_ConfigPinRemap(GPIO_RMP2_SPI2, ENABLE);
}
/*!< Configure sFLASH_SPI pins: SCK */
GPIO_InitStructure.Pin = sFLASH_SPI_SCK_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitPeripheral(sFLASH_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_SPI pins: MOSI */
GPIO_InitStructure.Pin = sFLASH_SPI_MOSI_PIN;
GPIO_InitPeripheral(sFLASH_SPI_MOSI_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_SPI pins: MISO */
GPIO_InitStructure.Pin = sFLASH_SPI_MISO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitPeripheral(sFLASH_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
/*!< Configure sFLASH_CS_PIN pin: sFLASH Card CS pin */
GPIO_InitStructure.Pin = sFLASH_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(sFLASH_CS_GPIO_PORT, &GPIO_InitStructure);
}
5.3.注意事项:查看SPI2使用的引脚,需要看一下复用功能,需不需要重映射配置;上例中使用了PE10~PE13,是需要进行重映射配置,要不然就无法通讯了!
5.4.SPI2测试环境
5.5.SPI2测试结果
6.工程源代码
- 2024-02-27
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】03、熟悉LIN主从机通讯(收发数据)
1.概述
上节我们熟悉了国民技术N32A455的CAN通讯,本节我们来熟悉国民技术N32A455的LIN通讯,在汽车电子组网应用中,通常CAN会作为高速通讯的网络,而LIN则会作为低事通讯的网络,这两个网络相互配合,实现了车机整体的通讯网络。
N32A455的LIN其实是基于通用同步异步收发器(USART)的LIN模式实现的,通过RX\TX引脚与LIN收发芯片连接,通过LIN底层通讯协议,实现LIN的数据交互。
2.LIN协议
这部分在UM手册上并没有过多的去描述,只提及到了LIN的断开帧;但在我们使用LIN通讯时,必须要先搞懂LIN通讯协议哈,所以网罗了一些LIN的资料,供大家借鉴哦
3.LIN示例程序
依据官方提供的LIN主、从机示例程序,例程功能如下:若接收到主机请求帧(0x3C)会打印接收到的8字节数据(0x0F);若接收到从机应答帧(0x3D)将发送8个字节应答数据(0x01)给到主机节点。
3.1.LIN主机实现
#include "main.h"
#include "lin_master.h"
M_LIN_EX_MSG M_TxMsg;
void SetFrameMsg(M_LIN_EX_MSG *dst_Msg, M_LIN_EX_MSG src_Msg)
{
int i = 0;
Memset(dst_Msg, 0, sizeof(M_LIN_EX_MSG));
dst_Msg->Check = src_Msg.Check;
dst_Msg->DataLen = src_Msg.DataLen;
dst_Msg->Sync = src_Msg.Sync;
dst_Msg->PID = src_Msg.PID;
for(i = 0; i < src_Msg.DataLen; i++)
{
dst_Msg->Data[i] = src_Msg.Data[i];
}
log_info("SetFrameMsg ID:0x%02x\r\n", dst_Msg->PID);
}
void SetFramePID(M_LIN_EX_MSG *src_Msg)
{
uint8_t p0 = 0, p1 = 0;
uint8_t LIN_ID = src_Msg->PID, PID = 0x00;
p0 = (LIN_ID & 0x01) ^ ((LIN_ID & 0x02) >> 1) ^ ((LIN_ID & 0x04) >> 2) ^ ((LIN_ID & 0x10) >> 4);//????
p0 = p0 & 0x01;
p1 = ~(((LIN_ID & 0x02) >> 1) ^ ((LIN_ID & 0x08) >> 3) ^ ((LIN_ID & 0x10) >> 4) ^ ((LIN_ID & 0x20) >> 5));
p1 = p1 & 0x01;
PID = (p1 << 7) | (p0 << 6) | LIN_ID;
src_Msg->PID = PID;
log_info("p0 = %02x;p1 = %02x;PID = %02x\r\n", p0, p1, PID);
}
uint8_t MasterGetCheckSum(uint8_t *pData, uint8_t len)
{
uint16_t check_sum_temp = 0;
uint8_t i;
for(i = 0; i < len; i++)
{
check_sum_temp += pData[i];
if(check_sum_temp > 0xFF)
{
check_sum_temp -= 0xFF;
}
}
return (~check_sum_temp) & 0xFF;
}
void SetFrameChecksum(M_LIN_EX_MSG *Msg)
{
uint8_t CheckSum = 0;
uint8_t len = Msg->DataLen;
if(Msg->Check)
{
CheckSum = MasterGetCheckSum(&Msg->PID, len + 1);
}
else
{
CheckSum = MasterGetCheckSum(Msg->Data, len);
}
if(len < 8)
{
Msg->Data[len] = CheckSum;
}
else
{
Msg->Check = CheckSum;
}
}
void MasterSendBytes(uint8_t *pBuf, uint8_t Len)
{
USART_Break_Frame_Send(USARTx);
while(Len--)
{
while(USART_Flag_Status_Get(USARTx, USART_FLAG_TXC ) == RESET);
USART_Data_Send(USARTx, *pBuf++);
}
while(USART_Flag_Status_Get(USARTx, USART_FLAG_TXC ) == RESET);
}
void MasterSendFrame(M_LIN_EX_MSG Msg)
{
if(Msg.DataLen)
{
MasterSendBytes(&Msg.Sync, Msg.DataLen + 3);
}
else
{
MasterSendBytes(&Msg.Sync, 2);
}
}
void FrameHandle(void)
{
uint8_t tmp_PID = M_TxMsg.PID;
SetFramePID(&M_TxMsg);
switch (tmp_PID)
{
case 0x3C://Master request frame
SetFrameChecksum(&M_TxMsg);
break;
case 0x3D://Slave reply frame
M_TxMsg.DataLen = 0;
break;
default:
break;
}
MasterSendFrame(M_TxMsg);
}
static ErrorStatus USART_ByteReceive(uint8_t *Data, uint32_t TimeOut)
{
uint32_t Counter = 0;
while((USART_Flag_Status_Get(USARTx, USART_FLAG_RXDNE) == RESET) && (Counter != TimeOut))
{
Counter++;
}
if(Counter != TimeOut)
{
*Data = (uint8_t)USART_Data_Receive(USARTx);
return SUCCESS;
}
else
{
return ERROR;
}
}
uint32_t Master_RecData(uint8_t *pdata, uint8_t length)
{
int i = 0;
uint8_t Data = 0;
uint32_t number = 0;
while(i < length)
{
i++;
if((USART_ByteReceive(&Data, SC_RECEIVE_TIMEOUT)) == SUCCESS)
{
pdata[number] = Data;
number++;
}
}
return number;
}
ErrorStatus WaitFrameRes(uint8_t *dst_data, uint8_t length)
{
//int i = 0;
int datalen = 0;
uint8_t recv_data[16];
uint8_t CheckSum = 0;
datalen = Master_RecData(recv_data, 16);
if(datalen)
{
#if 0
log_info("recv_data:");
for(i = 1; i < datalen; i++)
{
log_info("0x%x\r\n", recv_data[i]);
}
#endif
CheckSum = MasterGetCheckSum(recv_data, datalen - 1);
log_info("CheckSum:0x%x\r\n", CheckSum);
if(CheckSum == recv_data[datalen - 1])
{
if( (datalen - 2) > length)
{
Buffercopy(dst_data, &recv_data[0], length);
}
else
{
Buffercopy(dst_data, &recv_data[0], datalen - 1);
}
return SUCCESS;
}
}
return ERROR;
}
void TestMasterReqFrame(void)
{
int i = 0;
M_LIN_EX_MSG CurLINTxMsg;
CurLINTxMsg.Check = CLASSIC;
CurLINTxMsg.DataLen = 8;
CurLINTxMsg.Sync = 0x55;
CurLINTxMsg.PID = 0x3C;
for(i = 0; i < CurLINTxMsg.DataLen; i++)
{
CurLINTxMsg.Data[i] = 0x0F;
}
SetFrameMsg(&M_TxMsg, CurLINTxMsg);
FrameHandle();
}
void TestSlaveResFrame(void)
{
M_LIN_EX_MSG CurLINTxMsg;
CurLINTxMsg.Check = CLASSIC;
CurLINTxMsg.DataLen = 0;
CurLINTxMsg.Sync = 0x55;
CurLINTxMsg.PID = 0x3D;
SetFrameMsg(&M_TxMsg, CurLINTxMsg);
FrameHandle();
}
void TestLinMaster(void)
{
int i = 0, count = 0;
uint8_t recv_data[8];
TestMasterReqFrame();
delay_xms(20);
while(count < 4)
{
Memset(recv_data, 0, 8);
TestSlaveResFrame();
if(WaitFrameRes(recv_data, 8) == SUCCESS)
{
log_info("recv_data:\r\n");
for(i = 0; i < 8; i++)
{
log_info("recv_data[%d] = 0x%x\r\n", i, recv_data[i]);
}
break;
}
else
{
log_info("slave no response!!\r\n");
count++;
}
}
}
#include <stdio.h>
#include "main.h"
static uint8_t max_ms = 116;
/**
*\*\name delay_xms.
*\*\fun delay program.
*\*\param nms
*\*\return none
**/
void delay_xms(uint32_t nms)
{
uint16_t i;
uint16_t count_1 = nms / max_ms;
uint16_t count_2 = nms % max_ms;
if(0 == count_1)
{
systick_delay_ms(nms);
}
else
{
for(i = 0; i < count_1; i++)
{
systick_delay_ms(max_ms);
}
if(count_2 != 0)
{
systick_delay_ms(count_2);
}
}
}
/**
*\*\name Memset.
*\*\fun memery set a value.
*\*\param s source
*\*\param c value
*\*\param count number
*\*\return s
**/
void *Memset(void *s, s8 c, u32 count)
{
s8 *xs = (s8 *) s;
while (count--) // clear 17byte buffer
{
*xs++ = c;
}
return s;
}
/**
*\*\name Buffercopy.
*\*\fun Compares two buffers.
*\*\param pBuffer1
*\*\param pBuffer2
*\*\param buffer's length
*\*\return s
**/
void Buffercopy(uint8_t *dest, uint8_t *src, uint16_t BufferLength)
{
while (BufferLength--)
{
*dest = *src;
dest++;
src++;
}
}
/**
*\*\name main.
*\*\fun Main program.
*\*\param none
*\*\return none
**/
int main(void)
{
USART_InitType USART_InitStructure;
log_init();
printf("\r\n test LIN master mode\r\n");
/* System Clocks Configuration */
RCC_Configuration();
/* NVIC configuration */
NVIC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
/* USARTx configuration ------------------------------------------------------*/
USART_InitStructure.BaudRate = 9600;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
/* Configure USARTx */
USART_Initializes(USARTx, &USART_InitStructure);
/* Enable the USARTx LIN mode*/
USART_LIN_Break_Detect_Length_Set(USARTx,USART_LINBDL_10B);
USART_LIN_Enable(USARTx);
/* Enable the USARTx */
USART_Enable(USARTx);
while (1)
{
TestLinMaster();
delay_xms(500);
}
}
/**
*\*\name RCC_Configuration.
*\*\fun Configures the different system clocks.
*\*\param none
*\*\return none
**/
void RCC_Configuration(void)
{
/* Enable GPIO clock */
GPIO_AHBClkCmd(USARTx_GPIO_CLK);
RCC_APB2_Peripheral_Clock_Enable(RCC_APB2_PERIPH_AFIO);
/* Enable USARTx Clock */
USART_APBxClkCmd(USARTx_CLK);
}
/**
*\*\name NVIC_Configuration.
*\*\fun Configures the nested vectored interrupt controller.
*\*\param none
*\*\return none
**/
void NVIC_Configuration(void)
{
NVIC_InitType NVIC_InitStructure;
NVIC_Priority_Group_Set(NVIC_PER2_SUB2_PRIORITYGROUP);
/* Enable the USARTx Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Initializes(&NVIC_InitStructure);
}
/**
*\*\name GPIO_Configuration.
*\*\fun Configures the different GPIO ports.
*\*\param none
*\*\return none
**/
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_Structure_Initialize(&GPIO_InitStructure);
/* Configure USARTx Tx as alternate function push-pull */
GPIO_InitStructure.Pin = USARTx_TxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = USARTx_Tx_GPIO_AF;
GPIO_Peripheral_Initialize(USARTx_GPIO, &GPIO_InitStructure);
/* Configure USARTx Rx as alternate function push-pull */
GPIO_InitStructure.Pin = USARTx_RxPin;
GPIO_InitStructure.GPIO_Alternate = USARTx_Rx_GPIO_AF;
GPIO_Peripheral_Initialize(USARTx_GPIO, &GPIO_InitStructure);
}
3.2.LIN从机实现
#include "main.h"
#include "lin_driver.h"
LIN_STATE LinRxState = IDLE;
uint8_t LINRxDataIndex = 0;
LIN_EX_MSG LINRxDataBuffer[2];//双缓冲接收数据,可以减少数据出错概率
uint8_t IDType[64] = {ID_TYPE_SR};
uint8_t GotMsgFlag = 0;
LIN_EX_MSG *pLINMsg;
LIN_EX_MSG LINTxMsg;
void LIN_SendBytes(uint8_t *pBuf, uint8_t Len)
{
while(Len--)
{
while(USART_GetFlagStatus(USARTz, USART_FLAG_TXC ) == RESET);
USART_SendData(USARTz, *pBuf++);
}
while(USART_GetFlagStatus(USARTz, USART_FLAG_TXC ) == RESET);
}
uint8_t LIN_GetCheckSum(uint8_t *pData, uint8_t len)
{
uint16_t check_sum_temp = 0;
uint8_t i;
for(i = 0; i < len; i++)
{
check_sum_temp += pData[i];
if(check_sum_temp > 0xFF)
{
check_sum_temp -= 0xFF;
}
}
return (~check_sum_temp) & 0xFF;
}
void LIN_SetResp(uint8_t ID, uint8_t *pData, uint8_t Len, uint8_t CheckType)
{
uint8_t i = 0;
uint8_t CheckSum = 0;
if(Len > 8)
{
Len = 8;
}
LINTxMsg.PID = GET_PID(ID);
for(i = 0; i < Len; i++)
{
LINTxMsg.Data[i] = pData[i];
}
if(CheckType)
{
CheckSum = LIN_GetCheckSum(&LINTxMsg.PID, Len + 1);
}
else
{
CheckSum = LIN_GetCheckSum(LINTxMsg.Data, Len);
}
if(Len < 8)
{
LINTxMsg.Data[Len] = CheckSum;
}
else
{
LINTxMsg.Check = CheckSum;
}
LINTxMsg.DataLen = Len;
}
void LIN_EX_RxAsync(uint8_t data)
{
switch(LinRxState)
{
case IDLE:
break;
case SYNCH:
if(data == 0x55)
{
LINRxDataBuffer[LINRxDataIndex].Sync = 0x55;
LinRxState = ID_LEN;
}
else
{
LinRxState = IDLE;
}
break;
case ID_LEN:
if(GET_PID(data) == data)
{
LINRxDataBuffer[LINRxDataIndex].PID = data;
LINRxDataBuffer[LINRxDataIndex].DataLen = 0;
if(IDType[data & 0x3F] == ID_TYPE_SR)
{
LinRxState = DATA_GET;
}
else
{
//接收到主机发送的帧头,从机模式发送数据
if(((LINTxMsg.PID & 0x3F) == (data & 0x3F)) && (LINTxMsg.DataLen > 0))
{
LIN_SendBytes(LINTxMsg.Data, LINTxMsg.DataLen + 1);
LINTxMsg.DataLen = 0;
}
LinRxState = IDLE;
}
}
else
{
LinRxState = IDLE;
}
break;
case DATA_GET:
LINRxDataBuffer[LINRxDataIndex].Data[LINRxDataBuffer[LINRxDataIndex].DataLen] = data;
LINRxDataBuffer[LINRxDataIndex].Check = data;
LINRxDataBuffer[LINRxDataIndex].DataLen++;
if(LINRxDataBuffer[LINRxDataIndex].DataLen >= 8)
{
LinRxState = CHECKSUM;
}
else
{
LinRxState = DATA_GET;
}
break;
case CHECKSUM:
LINRxDataBuffer[LINRxDataIndex].Check = data;
pLINMsg = &LINRxDataBuffer[LINRxDataIndex];
GotMsgFlag = 1;
LINRxDataIndex = (LINRxDataIndex + 1) % 2;
LinRxState = IDLE;
break;
default:
break;
}
}
void LIN_IRQHandler(void)
{
//BREAK中断
if(USART_GetIntStatus(USARTz, USART_INT_LINBD) == SET)
{
USART_ClrIntPendingBit(USARTz, USART_INT_LINBD);//清除LIN间隔场检测标志位
//读状态寄存器和数据寄存器是为了清除FE标志
USARTz->STS;
USARTz->DAT;
LinRxState = SYNCH;
return;
}
//接收数据中断
if (USART_GetIntStatus(USARTz, USART_INT_RXDNE) == SET)
{
USART_ClrIntPendingBit(USARTz, USART_INT_RXDNE); //清除接收中断标志位
if(USART_GetIntStatus(USARTz, USART_INT_FEF) == RESET)
{
LIN_EX_RxAsync((uint8_t)USART_ReceiveData(USARTz));
}
}
}
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] 执行主机下发的命令
* @param pData 收到的数据,该函数会默认读取8字节数据
* @param pFunResp 命令响应函数指针,需要自己实现
* @retval 无
*/
void BOOT_ExecutiveCommand(uint8_t *pData, FUN_RESP pFunResp)
#if 1
{
int i = 0;
log_info("BOOT_ExecutiveCommand\r\n");
for( i = 0; i < 8; i++)
{
log_info("pData[%d] = %02x \r\n", i, pData[i]);
pData[i] = 0x1;
}
pFunResp(pData, 8);
}
#endif
#include <stdio.h>
#include "main.h"
/** @addtogroup N32A45X_StdPeriph_Examples
* @{
*/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
static uint8_t max_ms = 116;
extern uint8_t IDType[64];
extern uint8_t GotMsgFlag;
extern LIN_EX_MSG *pLINMsg;
void delay_xms(uint32_t nms)
{
uint16_t i;
uint16_t count_1 = nms / max_ms;
uint16_t count_2 = nms % max_ms;
if(0 == count_1)
{
systick_delay_ms(nms);
}
else
{
for(i = 0; i < count_1; i++)
{
systick_delay_ms(max_ms);
}
if(count_2 != 0)
{
systick_delay_ms(count_2);
}
}
}
/**
* @brief Compares two buffers.
* @param pBuffer1, pBuffer2: buffers to be compared.
* @param BufferLength buffer's length
* [url=home.php?mod=space&uid=784970]@return[/url] PASSED: pBuffer1 identical to pBuffer2
* FAILED: pBuffer1 differs from pBuffer2
*/
void Buffercopy(uint8_t *dest, uint8_t *src, uint16_t BufferLength)
{
while (BufferLength--)
{
*dest = *src;
dest++;
src++;
}
}
void LIN_RespData(uint8_t *pData, uint8_t Len)
{
LIN_SetResp(MSG_SEND_ID, pData, Len, CHECK_TYPE);
}
/**
* @brief Main program
*/
int main(void)
{
USART_InitType USART_InitStructure;
log_init();
printf("\r\n test LIN slave mode\r\n");
/* System Clocks Configuration */
RCC_Configuration();
/* NVIC configuration */
NVIC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
/* USARTy and USARTz configuration ------------------------------------------------------*/
USART_InitStructure.BaudRate = 9600;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
/* Configure USARTy and USARTz */
USART_Init(USARTz, &USART_InitStructure);
/* Enable the USARTz LIN mode*/
USART_ConfigLINBreakDetectLength(USARTz, USART_LINBDL_10B);
USART_EnableLIN(USARTz, ENABLE);
/* Enable USARTz Receive and Transmit interrupts */
USART_ConfigInt(USARTz, USART_INT_RXDNE, ENABLE);
//USART_ConfigInt(USARTz, USART_INT_TXDE, ENABLE);
USART_ConfigInt(USARTz, USART_INT_LINBD, ENABLE);
/* Enable the USARTz */
USART_Enable(USARTz, ENABLE);
//配置从机ID模式
IDType[MSG_RECEIVE_ID & 0x3F] = ID_TYPE_SR;
IDType[MSG_SEND_ID & 0x3F] = ID_TYPE_SW;
while (1)
{
if(GotMsgFlag)
{
BOOT_ExecutiveCommand(pLINMsg->Data, LIN_RespData);
GotMsgFlag = 0;
}
}
}
/**
* @brief Configures the different system clocks.
*/
void RCC_Configuration(void)
{
/* Enable GPIO clock */
RCC_EnableAPB2PeriphClk(USARTz_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE);
/* Enable USARTz Clock */
USARTz_APBxClkCmd(USARTz_CLK, ENABLE);
}
/**
* @brief Configures the different GPIO ports.
*/
void GPIO_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
/* Configure USARTz Rx as input floating */
GPIO_InitStructure.Pin = USARTz_RxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitPeripheral(USARTz_GPIO, &GPIO_InitStructure);
/* Configure USARTz Tx as alternate function push-pull */
GPIO_InitStructure.Pin = USARTz_TxPin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitPeripheral(USARTz_GPIO, &GPIO_InitStructure);
/* Configure TJA1027 SLP as ouput push-pull */
GPIO_InitStructure.Pin = SLP_Pin;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(SLP_GPIO, &GPIO_InitStructure);
GPIO_SetBits(SLP_GPIO,SLP_Pin);
#ifdef _USART2_
GPIO_ConfigPinRemap(GPIO_RMP3_USART2, ENABLE);
GPIO_ConfigPinRemap(GPIO_RMP_SW_JTAG_NO_NJTRST, ENABLE);
#endif
#ifdef _USART4_
GPIO_ConfigPinRemap(GPIO_RMP3_UART4, ENABLE);
#endif
}
/**
* @brief Configures the nested vectored interrupt controller.
*/
void NVIC_Configuration(void)
{
NVIC_InitType NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
/* Enable the USARTz Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USARTz_IRQn;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file pointer to the source file name
* @param line assert_param error line source number
*/
void assert_failed(const uint8_t *expr, const uint8_t *file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
4.测试
4.1.测试环境
由于没有2块N32A455开发板,所以我找了一块N32G430C8L7_STB_V1.0开发板作为LIN主机,搭配N32A455开发板作为LIN从机一起测试;但是N32G430C8L7_STB_V1.0开发板上并没有板载LIN收发芯片,所以我们还是通过交叉连接USART的RX和TX,对LIN的通讯功能进行测试,毕竟功能OK,其它只是固定的外围硬件电路,关系不大!
4.2.测试结果
5.注意事项
5.1、当使用N32A455的USART作为LIN模式通讯时,以下配置位必须全部被清零 :USART_CTRL2.STPB[1:0] 、USART_CTRL2.CLKEN 、USART_CTRL3.SCMEN 、USART_CTRL3.HDMEN 、USART_CTRL3.IRDAMEN。
5.2.在 LIN 模式下发送数据时,数据长度只能配置为 8 位。
- 2024-02-26
-
发表了主题帖:
【小华工控新品HC32F448】08.有工控显示需求?HC32F448帮你搞定!
1.概述
小华H32F448系列是基于ARM Cortex-M4 32-bit RISC CPU内核的MCU,最高工作频率可达到200MHz,内核集成了FPU和DSP,实现单精度浮点算术运算,支持所有ARM单精度数据处理指令和数据类型,支持完整的DSP指令集;在支持高算力的同时,还支持外部存储器控制EXMC,在有工控显示需要的应用领域,提供更优的解决方案。
外部存储器控制器 EXMC(External Memory Controller)是一个用来访问各种片外存储器,实现数据交换的独立模块。 EXMC 通过配置可以把内部的 AMBA 协议接口转换为各种类型的专用片外存储器通信协议接口,包括 SRAM、 PSRAM、 NOR Flash 等。
2.功能列表
EXMC 基本的功能列表如下所示:
3.原理图
4.例程功能
参考示例程序,我们在网上购买了一款4.3寸,带电容触摸的TFT显示屏,对EXMC功能进行学习,通过示例程序中的功能进行测试:LCD屏幕画出正方形,触摸正方形所在区域,平移正方形位置;LCD屏幕画出圆形和红、绿、蓝三色全屏
5.示例程序
EXMC初始化配置:
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] Initializes LCD low level.
* @param None
* @retval int32_t:
* - LL_OK: Initialize successfully.
* - LL_ERR: Initialize unsuccessfully.
*/
static int32_t LCD_SMC_Init(void)
{
__IO uint32_t u32To = 0UL;
int32_t i32Ret = LL_OK;
stc_exmc_smc_init_t stcSmcInit;
stc_exmc_smc_chip_config_t stcChipConfig;
stc_exmc_smc_timing_config_t stcTimingConfig;
en_flag_status_t enChipStatus = RESET;
en_flag_status_t enTimingStatus = RESET;
LCD_Port_Init();
/* Enable SMC clock */
FCG_Fcg3PeriphClockCmd(FCG3_PERIPH_SMC, ENABLE);
/* Enable SMC. */
EXMC_SMC_Cmd(ENABLE);
EXMC_SMC_ExitLowPower();
while (EXMC_SMC_READY != EXMC_SMC_GetStatus()) {
if (u32To > SMC_MAX_TIMEOUT) {
i32Ret = LL_ERR;
break;
}
u32To++;
}
if (LL_OK == i32Ret) {
/* Configure SMC width && CS &chip & timing. */
(void)EXMC_SMC_StructInit(&stcSmcInit);
stcSmcInit.stcChipConfig.u32AddrMatch = BSP_NT35510_MATCH_ADDR;
stcSmcInit.stcChipConfig.u32AddrMask = BSP_NT35510_MASK_ADDR;
stcSmcInit.stcChipConfig.u32MemoryWidth = EXMC_SMC_MEMORY_WIDTH_16BIT;
stcSmcInit.stcChipConfig.u32BAA = EXMC_SMC_BAA_PORT_DISABLE;
stcSmcInit.stcChipConfig.u32ADV = EXMC_SMC_ADV_PORT_DISABLE;
stcSmcInit.stcChipConfig.u32BLS = EXMC_SMC_BLS_SYNC_CS;
stcSmcInit.stcChipConfig.u32ReadMode = EXMC_SMC_READ_ASYNC;
stcSmcInit.stcChipConfig.u32WriteMode = EXMC_SMC_WRITE_ASYNC;
/* EXCLK bus frequency@40MHz: 3.3V */
stcSmcInit.stcTimingConfig.u8RC = 4U;
stcSmcInit.stcTimingConfig.u8WC = 2U;
stcSmcInit.stcTimingConfig.u8CEOE = 1U;
stcSmcInit.stcTimingConfig.u8WP = 1U;
stcSmcInit.stcTimingConfig.u8TR = 1U;
(void)EXMC_SMC_Init(BSP_NT35510_CHIP, &stcSmcInit);
/* Set command: updateregs */
EXMC_SMC_SetCommand(BSP_NT35510_CHIP, EXMC_SMC_CMD_UPDATEREGS, 0UL, 0UL);
/* Check timing status */
u32To = 0UL;
while ((enChipStatus != SET) || (enTimingStatus != SET)) {
(void)EXMC_SMC_GetTimingConfig(BSP_NT35510_CHIP, &stcTimingConfig);
if (0 == memcmp(&stcTimingConfig, &stcSmcInit.stcTimingConfig, sizeof(stcTimingConfig))) {
enTimingStatus = SET;
}
(void)EXMC_SMC_GetChipConfig(BSP_NT35510_CHIP, &stcChipConfig);
if (0 == memcmp(&stcChipConfig, &stcSmcInit.stcChipConfig, sizeof(stcChipConfig))) {
enChipStatus = SET;
}
if (u32To > SMC_MAX_TIMEOUT) {
i32Ret = LL_ERR;
break;
}
u32To++;
}
}
return i32Ret;
}
基于EXMC的显示屏驱动配置和基础函数实现:
/**
* @brief LCD delay
* @param [in] u32Delay: Delay in ms
* @retval None
*/
static void LCD_Delay(uint32_t u32Delay)
{
volatile uint32_t i;
const uint32_t u32Cyc = 24000UL;
while (u32Delay-- > 0UL) {
i = u32Cyc;
while (i-- > 0UL) {
;
}
}
}
/**
* @brief Configure LCD NT35310
* @param [in] pstcLCD: LCD controller
* @retval None
*/
static void LCD_NT35310_Config(stc_lcd_controller_t *pstcLCD)
{
NT35510_WriteReg(pstcLCD, 0xED);
NT35510_WriteData(pstcLCD, 0x01);
NT35510_WriteData(pstcLCD, 0xFE);
NT35510_WriteReg(pstcLCD, 0xEE);
NT35510_WriteData(pstcLCD, 0xDE);
NT35510_WriteData(pstcLCD, 0x21);
NT35510_WriteReg(pstcLCD, 0xF1);
NT35510_WriteData(pstcLCD, 0x01);
NT35510_WriteReg(pstcLCD, 0xDF);
NT35510_WriteData(pstcLCD, 0x10);
//VCOMvoltage//
NT35510_WriteReg(pstcLCD, 0xC4);
NT35510_WriteData(pstcLCD, 0x8F);
NT35510_WriteReg(pstcLCD, 0xC6);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xE2);
NT35510_WriteData(pstcLCD, 0xE2);
NT35510_WriteData(pstcLCD, 0xE2);
NT35510_WriteReg(pstcLCD, 0xBF);
NT35510_WriteData(pstcLCD, 0xAA);
NT35510_WriteReg(pstcLCD, 0xB0);
NT35510_WriteData(pstcLCD, 0x0D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x0D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x11);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x19);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x21);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x2D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x5D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x5D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB1);
NT35510_WriteData(pstcLCD, 0x80);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x8B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x96);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x02);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x03);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB4);
NT35510_WriteData(pstcLCD, 0x8B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x96);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA1);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB5);
NT35510_WriteData(pstcLCD, 0x02);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x03);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x04);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB6);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB7);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3F);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x5E);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x64);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x8C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xAC);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xDC);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x70);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x90);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xEB);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xDC);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xB8);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xBA);
NT35510_WriteData(pstcLCD, 0x24);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC1);
NT35510_WriteData(pstcLCD, 0x20);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x54);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xFF);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC2);
NT35510_WriteData(pstcLCD, 0x0A);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x04);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC3);
NT35510_WriteData(pstcLCD, 0x3C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3A);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x39);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x37);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x36);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x32);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x2F);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x2C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x29);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x26);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x24);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x24);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x23);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x36);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x32);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x2F);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x2C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x29);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x26);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x24);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x24);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x23);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC4);
NT35510_WriteData(pstcLCD, 0x62);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x05);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x84);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF0);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x18);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA4);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x18);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x50);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x0C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x17);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x95);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xE6);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC5);
NT35510_WriteData(pstcLCD, 0x32);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x65);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x76);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x88);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC6);
NT35510_WriteData(pstcLCD, 0x20);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x17);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x01);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC7);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC8);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xC9);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE0);
NT35510_WriteData(pstcLCD, 0x16);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x1C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x21);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x36);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x46);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x52);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x64);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x7A);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x8B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA8);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xB9);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC4);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xCA);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD9);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xE0);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE1);
NT35510_WriteData(pstcLCD, 0x16);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x1C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x22);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x36);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x45);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x52);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x64);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x7A);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x8B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA8);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xB9);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC4);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xCA);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD8);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xE0);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE2);
NT35510_WriteData(pstcLCD, 0x05);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x0B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x1B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x34);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x4F);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x61);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x79);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x88);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x97);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA6);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xB7);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC7);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD1);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD6);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xDD);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE3);
NT35510_WriteData(pstcLCD, 0x05);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x1C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x33);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x50);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x62);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x78);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x88);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x97);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA6);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xB7);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC7);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD1);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD5);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xDD);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE4);
NT35510_WriteData(pstcLCD, 0x01);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x01);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x02);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x2A);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x4B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x5D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x74);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x84);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x93);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xB3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xBE);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC4);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xCD);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xDD);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE5);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x02);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x29);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x3C);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x4B);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x5D);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x74);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x84);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x93);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xA2);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xB3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xBE);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xC4);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xCD);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xD3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xDC);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE6);
NT35510_WriteData(pstcLCD, 0x11);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x34);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x56);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x76);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x77);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x66);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x88);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xBB);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x66);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x45);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x43);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE7);
NT35510_WriteData(pstcLCD, 0x32);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x76);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x66);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x67);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x67);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x87);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xBB);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x77);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x56);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x23);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x33);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x45);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE8);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x87);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x88);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x77);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x66);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x88);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xAA);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xBB);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x99);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x66);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x44);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xE9);
NT35510_WriteData(pstcLCD, 0xAA);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0xAA);
NT35510_WriteReg(pstcLCD, 0xCF);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xF0);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x50);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xF3);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0xF9);
NT35510_WriteData(pstcLCD, 0x06);
NT35510_WriteData(pstcLCD, 0x10);
NT35510_WriteData(pstcLCD, 0x29);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0x3A);
NT35510_WriteData(pstcLCD, 0x55);
NT35510_WriteReg(pstcLCD, 0x11);
LCD_Delay(100);
NT35510_WriteReg(pstcLCD, 0x29);
NT35510_WriteReg(pstcLCD, 0x35);
NT35510_WriteData(pstcLCD, 0x00);
NT35510_WriteReg(pstcLCD, 0x51);
NT35510_WriteData(pstcLCD, 0xFF);
NT35510_WriteReg(pstcLCD, 0x53);
NT35510_WriteData(pstcLCD, 0x2C);
NT35510_WriteReg(pstcLCD, 0x55);
NT35510_WriteData(pstcLCD, 0x82);
NT35510_WriteReg(pstcLCD, 0x2c);
}
/**
* @brief Configure LCD NT35510
* @param [in] pstcLCD: LCD controller
* @retval None
*/
static void LCD_NT35510_Config(stc_lcd_controller_t *pstcLCD)
{
/* Config LCD */
NT35510_WriteRegData(pstcLCD, 0xF000U, 0x55U);
NT35510_WriteRegData(pstcLCD, 0xF001U, 0xAAU);
NT35510_WriteRegData(pstcLCD, 0xF002U, 0x52U);
NT35510_WriteRegData(pstcLCD, 0xF003U, 0x08U);
NT35510_WriteRegData(pstcLCD, 0xF004U, 0x01U);
/* AVDD Set AVDD 5.2V */
NT35510_WriteRegData(pstcLCD, 0xB000U, 0x0DU);
NT35510_WriteRegData(pstcLCD, 0xB001U, 0x0DU);
NT35510_WriteRegData(pstcLCD, 0xB002U, 0x0DU);
/* AVDD ratio */
NT35510_WriteRegData(pstcLCD, 0xB600U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xB601U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xB602U, 0x34U);
/* AVEE -5.2V */
NT35510_WriteRegData(pstcLCD, 0xB100U, 0x0DU);
NT35510_WriteRegData(pstcLCD, 0xB101U, 0x0DU);
NT35510_WriteRegData(pstcLCD, 0xB102U, 0x0DU);
/* AVEE ratio */
NT35510_WriteRegData(pstcLCD, 0xB700U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xB701U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xB702U, 0x34U);
/* VCL -2.5V */
NT35510_WriteRegData(pstcLCD, 0xB200U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xB201U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xB202U, 0x00U);
/* VCL ratio */
NT35510_WriteRegData(pstcLCD, 0xB800U, 0x24U);
NT35510_WriteRegData(pstcLCD, 0xB801U, 0x24U);
NT35510_WriteRegData(pstcLCD, 0xB802U, 0x24U);
/* VGH 15V (Free pump) */
NT35510_WriteRegData(pstcLCD, 0xBF00U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xB300U, 0x0FU);
NT35510_WriteRegData(pstcLCD, 0xB301U, 0x0FU);
NT35510_WriteRegData(pstcLCD, 0xB302U, 0x0FU);
/* VGH ratio */
NT35510_WriteRegData(pstcLCD, 0xB900U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xB901U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xB902U, 0x34U);
/* VGL_REG -10V */
NT35510_WriteRegData(pstcLCD, 0xB500U, 0x08U);
NT35510_WriteRegData(pstcLCD, 0xB501U, 0x08U);
NT35510_WriteRegData(pstcLCD, 0xB502U, 0x08U);
NT35510_WriteRegData(pstcLCD, 0xC200U, 0x03U);
/* VGLX ratio */
NT35510_WriteRegData(pstcLCD, 0xBA00U, 0x24U);
NT35510_WriteRegData(pstcLCD, 0xBA01U, 0x24U);
NT35510_WriteRegData(pstcLCD, 0xBA02U, 0x24U);
/* VGMP/VGSP 4.5V/0V */
NT35510_WriteRegData(pstcLCD, 0xBC00U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xBC01U, 0x78U);
NT35510_WriteRegData(pstcLCD, 0xBC02U, 0x00U);
/* VGMN/VGSN -4.5V/0V */
NT35510_WriteRegData(pstcLCD, 0xBD00U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xBD01U, 0x78U);
NT35510_WriteRegData(pstcLCD, 0xBD02U, 0x00U);
/* VCOM */
NT35510_WriteRegData(pstcLCD, 0xBE00U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xBE01U, 0x64U);
/* Gamma Setting */
NT35510_WriteRegData(pstcLCD, 0xD100U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD101U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD102U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD103U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD104U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD105U, 0x3AU);
NT35510_WriteRegData(pstcLCD, 0xD106U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD107U, 0x4AU);
NT35510_WriteRegData(pstcLCD, 0xD108U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD109U, 0x5CU);
NT35510_WriteRegData(pstcLCD, 0xD10AU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD10BU, 0x81U);
NT35510_WriteRegData(pstcLCD, 0xD10CU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD10DU, 0xA6U);
NT35510_WriteRegData(pstcLCD, 0xD10EU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD10FU, 0xE5U);
NT35510_WriteRegData(pstcLCD, 0xD110U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD111U, 0x13U);
NT35510_WriteRegData(pstcLCD, 0xD112U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD113U, 0x54U);
NT35510_WriteRegData(pstcLCD, 0xD114U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD115U, 0x82U);
NT35510_WriteRegData(pstcLCD, 0xD116U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD117U, 0xCAU);
NT35510_WriteRegData(pstcLCD, 0xD118U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD119U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD11AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD11BU, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD11CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD11DU, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD11EU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD11FU, 0x67U);
NT35510_WriteRegData(pstcLCD, 0xD120U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD121U, 0x84U);
NT35510_WriteRegData(pstcLCD, 0xD122U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD123U, 0xA4U);
NT35510_WriteRegData(pstcLCD, 0xD124U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD125U, 0xB7U);
NT35510_WriteRegData(pstcLCD, 0xD126U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD127U, 0xCFU);
NT35510_WriteRegData(pstcLCD, 0xD128U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD129U, 0xDEU);
NT35510_WriteRegData(pstcLCD, 0xD12AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD12BU, 0xF2U);
NT35510_WriteRegData(pstcLCD, 0xD12CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD12DU, 0xFEU);
NT35510_WriteRegData(pstcLCD, 0xD12EU, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD12FU, 0x10U);
NT35510_WriteRegData(pstcLCD, 0xD130U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD131U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD132U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD133U, 0x6DU);
NT35510_WriteRegData(pstcLCD, 0xD200U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD201U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD202U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD203U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD204U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD205U, 0x3AU);
NT35510_WriteRegData(pstcLCD, 0xD206U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD207U, 0x4AU);
NT35510_WriteRegData(pstcLCD, 0xD208U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD209U, 0x5CU);
NT35510_WriteRegData(pstcLCD, 0xD20AU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD20BU, 0x81U);
NT35510_WriteRegData(pstcLCD, 0xD20CU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD20DU, 0xA6U);
NT35510_WriteRegData(pstcLCD, 0xD20EU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD20FU, 0xE5U);
NT35510_WriteRegData(pstcLCD, 0xD210U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD211U, 0x13U);
NT35510_WriteRegData(pstcLCD, 0xD212U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD213U, 0x54U);
NT35510_WriteRegData(pstcLCD, 0xD214U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD215U, 0x82U);
NT35510_WriteRegData(pstcLCD, 0xD216U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD217U, 0xCAU);
NT35510_WriteRegData(pstcLCD, 0xD218U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD219U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD21AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD21BU, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD21CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD21DU, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD21EU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD21FU, 0x67U);
NT35510_WriteRegData(pstcLCD, 0xD220U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD221U, 0x84U);
NT35510_WriteRegData(pstcLCD, 0xD222U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD223U, 0xA4U);
NT35510_WriteRegData(pstcLCD, 0xD224U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD225U, 0xB7U);
NT35510_WriteRegData(pstcLCD, 0xD226U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD227U, 0xCFU);
NT35510_WriteRegData(pstcLCD, 0xD228U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD229U, 0xDEU);
NT35510_WriteRegData(pstcLCD, 0xD22AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD22BU, 0xF2U);
NT35510_WriteRegData(pstcLCD, 0xD22CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD22DU, 0xFEU);
NT35510_WriteRegData(pstcLCD, 0xD22EU, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD22FU, 0x10U);
NT35510_WriteRegData(pstcLCD, 0xD230U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD231U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD232U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD233U, 0x6DU);
NT35510_WriteRegData(pstcLCD, 0xD300U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD301U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD302U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD303U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD304U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD305U, 0x3AU);
NT35510_WriteRegData(pstcLCD, 0xD306U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD307U, 0x4AU);
NT35510_WriteRegData(pstcLCD, 0xD308U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD309U, 0x5CU);
NT35510_WriteRegData(pstcLCD, 0xD30AU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD30BU, 0x81U);
NT35510_WriteRegData(pstcLCD, 0xD30CU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD30DU, 0xA6U);
NT35510_WriteRegData(pstcLCD, 0xD30EU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD30FU, 0xE5U);
NT35510_WriteRegData(pstcLCD, 0xD310U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD311U, 0x13U);
NT35510_WriteRegData(pstcLCD, 0xD312U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD313U, 0x54U);
NT35510_WriteRegData(pstcLCD, 0xD314U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD315U, 0x82U);
NT35510_WriteRegData(pstcLCD, 0xD316U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD317U, 0xCAU);
NT35510_WriteRegData(pstcLCD, 0xD318U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD319U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD31AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD31BU, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD31CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD31DU, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD31EU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD31FU, 0x67U);
NT35510_WriteRegData(pstcLCD, 0xD320U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD321U, 0x84U);
NT35510_WriteRegData(pstcLCD, 0xD322U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD323U, 0xA4U);
NT35510_WriteRegData(pstcLCD, 0xD324U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD325U, 0xB7U);
NT35510_WriteRegData(pstcLCD, 0xD326U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD327U, 0xCFU);
NT35510_WriteRegData(pstcLCD, 0xD328U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD329U, 0xDEU);
NT35510_WriteRegData(pstcLCD, 0xD32AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD32BU, 0xF2U);
NT35510_WriteRegData(pstcLCD, 0xD32CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD32DU, 0xFEU);
NT35510_WriteRegData(pstcLCD, 0xD32EU, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD32FU, 0x10U);
NT35510_WriteRegData(pstcLCD, 0xD330U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD331U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD332U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD333U, 0x6DU);
NT35510_WriteRegData(pstcLCD, 0xD400U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD401U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD402U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD403U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD404U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD405U, 0x3AU);
NT35510_WriteRegData(pstcLCD, 0xD406U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD407U, 0x4AU);
NT35510_WriteRegData(pstcLCD, 0xD408U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD409U, 0x5CU);
NT35510_WriteRegData(pstcLCD, 0xD40AU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD40BU, 0x81U);
NT35510_WriteRegData(pstcLCD, 0xD40CU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD40DU, 0xA6U);
NT35510_WriteRegData(pstcLCD, 0xD40EU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD40FU, 0xE5U);
NT35510_WriteRegData(pstcLCD, 0xD410U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD411U, 0x13U);
NT35510_WriteRegData(pstcLCD, 0xD412U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD413U, 0x54U);
NT35510_WriteRegData(pstcLCD, 0xD414U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD415U, 0x82U);
NT35510_WriteRegData(pstcLCD, 0xD416U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD417U, 0xCAU);
NT35510_WriteRegData(pstcLCD, 0xD418U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD419U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD41AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD41BU, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD41CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD41DU, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD41EU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD41FU, 0x67U);
NT35510_WriteRegData(pstcLCD, 0xD420U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD421U, 0x84U);
NT35510_WriteRegData(pstcLCD, 0xD422U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD423U, 0xA4U);
NT35510_WriteRegData(pstcLCD, 0xD424U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD425U, 0xB7U);
NT35510_WriteRegData(pstcLCD, 0xD426U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD427U, 0xCFU);
NT35510_WriteRegData(pstcLCD, 0xD428U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD429U, 0xDEU);
NT35510_WriteRegData(pstcLCD, 0xD42AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD42BU, 0xF2U);
NT35510_WriteRegData(pstcLCD, 0xD42CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD42DU, 0xFEU);
NT35510_WriteRegData(pstcLCD, 0xD42EU, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD42FU, 0x10U);
NT35510_WriteRegData(pstcLCD, 0xD430U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD431U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD432U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD433U, 0x6DU);
NT35510_WriteRegData(pstcLCD, 0xD500U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD501U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD502U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD503U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD504U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD505U, 0x3AU);
NT35510_WriteRegData(pstcLCD, 0xD506U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD507U, 0x4AU);
NT35510_WriteRegData(pstcLCD, 0xD508U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD509U, 0x5CU);
NT35510_WriteRegData(pstcLCD, 0xD50AU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD50BU, 0x81U);
NT35510_WriteRegData(pstcLCD, 0xD50CU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD50DU, 0xA6U);
NT35510_WriteRegData(pstcLCD, 0xD50EU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD50FU, 0xE5U);
NT35510_WriteRegData(pstcLCD, 0xD510U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD511U, 0x13U);
NT35510_WriteRegData(pstcLCD, 0xD512U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD513U, 0x54U);
NT35510_WriteRegData(pstcLCD, 0xD514U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD515U, 0x82U);
NT35510_WriteRegData(pstcLCD, 0xD516U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD517U, 0xCAU);
NT35510_WriteRegData(pstcLCD, 0xD518U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD519U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD51AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD51BU, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD51CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD51DU, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD51EU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD51FU, 0x67U);
NT35510_WriteRegData(pstcLCD, 0xD520U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD521U, 0x84U);
NT35510_WriteRegData(pstcLCD, 0xD522U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD523U, 0xA4U);
NT35510_WriteRegData(pstcLCD, 0xD524U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD525U, 0xB7U);
NT35510_WriteRegData(pstcLCD, 0xD526U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD527U, 0xCFU);
NT35510_WriteRegData(pstcLCD, 0xD528U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD529U, 0xDEU);
NT35510_WriteRegData(pstcLCD, 0xD52AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD52BU, 0xF2U);
NT35510_WriteRegData(pstcLCD, 0xD52CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD52DU, 0xFEU);
NT35510_WriteRegData(pstcLCD, 0xD52EU, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD52FU, 0x10U);
NT35510_WriteRegData(pstcLCD, 0xD530U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD531U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD532U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD533U, 0x6DU);
NT35510_WriteRegData(pstcLCD, 0xD600U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD601U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD602U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD603U, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD604U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD605U, 0x3AU);
NT35510_WriteRegData(pstcLCD, 0xD606U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD607U, 0x4AU);
NT35510_WriteRegData(pstcLCD, 0xD608U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD609U, 0x5CU);
NT35510_WriteRegData(pstcLCD, 0xD60AU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD60BU, 0x81U);
NT35510_WriteRegData(pstcLCD, 0xD60CU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD60DU, 0xA6U);
NT35510_WriteRegData(pstcLCD, 0xD60EU, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD60FU, 0xE5U);
NT35510_WriteRegData(pstcLCD, 0xD610U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD611U, 0x13U);
NT35510_WriteRegData(pstcLCD, 0xD612U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD613U, 0x54U);
NT35510_WriteRegData(pstcLCD, 0xD614U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD615U, 0x82U);
NT35510_WriteRegData(pstcLCD, 0xD616U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD617U, 0xCAU);
NT35510_WriteRegData(pstcLCD, 0xD618U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD619U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xD61AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD61BU, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xD61CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD61DU, 0x34U);
NT35510_WriteRegData(pstcLCD, 0xD61EU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD61FU, 0x67U);
NT35510_WriteRegData(pstcLCD, 0xD620U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD621U, 0x84U);
NT35510_WriteRegData(pstcLCD, 0xD622U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD623U, 0xA4U);
NT35510_WriteRegData(pstcLCD, 0xD624U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD625U, 0xB7U);
NT35510_WriteRegData(pstcLCD, 0xD626U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD627U, 0xCFU);
NT35510_WriteRegData(pstcLCD, 0xD628U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD629U, 0xDEU);
NT35510_WriteRegData(pstcLCD, 0xD62AU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD62BU, 0xF2U);
NT35510_WriteRegData(pstcLCD, 0xD62CU, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xD62DU, 0xFEU);
NT35510_WriteRegData(pstcLCD, 0xD62EU, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD62FU, 0x10U);
NT35510_WriteRegData(pstcLCD, 0xD630U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD631U, 0x33U);
NT35510_WriteRegData(pstcLCD, 0xD632U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xD633U, 0x6DU);
/* LV2 Page 0 enable */
NT35510_WriteRegData(pstcLCD, 0xF000U, 0x55U);
NT35510_WriteRegData(pstcLCD, 0xF001U, 0xAAU);
NT35510_WriteRegData(pstcLCD, 0xF002U, 0x52U);
NT35510_WriteRegData(pstcLCD, 0xF003U, 0x08U);
NT35510_WriteRegData(pstcLCD, 0xF004U, 0x00U);
/* Display control */
NT35510_WriteRegData(pstcLCD, 0xB100U, 0xCCU);
NT35510_WriteRegData(pstcLCD, 0xB101U, 0x00U);
/* Source hold time */
NT35510_WriteRegData(pstcLCD, 0xB600U, 0x05U);
/* Gate EQ control */
NT35510_WriteRegData(pstcLCD, 0xB700U, 0x70U);
NT35510_WriteRegData(pstcLCD, 0xB701U, 0x70U);
/* Source EQ control (Mode 2) */
NT35510_WriteRegData(pstcLCD, 0xB800U, 0x01U);
NT35510_WriteRegData(pstcLCD, 0xB801U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xB802U, 0x03U);
NT35510_WriteRegData(pstcLCD, 0xB803U, 0x03U);
/* Inversion mode (2-dot) */
NT35510_WriteRegData(pstcLCD, 0xBC00U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xBC01U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0xBC02U, 0x00U);
/* Timing control 4H w/ 4-delay */
NT35510_WriteRegData(pstcLCD, 0xC900U, 0xD0U);
NT35510_WriteRegData(pstcLCD, 0xC901U, 0x02U);
NT35510_WriteRegData(pstcLCD, 0xC902U, 0x50U);
NT35510_WriteRegData(pstcLCD, 0xC903U, 0x50U);
NT35510_WriteRegData(pstcLCD, 0xC904U, 0x50U);
NT35510_WriteRegData(pstcLCD, 0x3500U, 0x00U);
NT35510_WriteRegData(pstcLCD, 0x3A00U, 0x55U); /* 16-bit/pixel */
NT35510_WriteReg(pstcLCD, 0x1100U);
LCD_Delay(120UL);
NT35510_WriteReg(pstcLCD, 0x2900U);
}
/**
* @}
*/
/**
* @defgroup NT35510_Global_Functions NT35510 Global Functions
* @{
*/
/**
* @brief Initialize LCD device.
* @param [in] pstcLCD: LCD controller
* @retval None
*/
void NT35510_Init(stc_lcd_controller_t *pstcLCD)
{
uint16_t u16ID;
if (NULL != pstcLCD) {
/* NOP */
NT35510_WriteRegData(pstcLCD, 0x0000U, 0x00U);
/* Read ID */
u16ID = NT35510_ReadID(pstcLCD);
if (0x5310U == u16ID) {
LCD_NT35310_Config(pstcLCD);
m_stcLcdDevice.u16Width = 320U;
m_stcLcdDevice.u16Height = 480U;
m_stcLcdDevice.u16WRamCmd = 0x2CU;
m_stcLcdDevice.u16SetXCmd = 0x2AU;
m_stcLcdDevice.u16SetYCmd = 0x2BU;
} else if (0x5510U == u16ID) {
LCD_NT35510_Config(pstcLCD);
m_stcLcdDevice.u16Width = 480U;
m_stcLcdDevice.u16Height = 800U;
m_stcLcdDevice.u16WRamCmd = 0x2C00U;
m_stcLcdDevice.u16SetXCmd = 0x2A00U;
m_stcLcdDevice.u16SetYCmd = 0x2B00U;
} else {
/* Unsupported LCD */
}
m_stcLcdDevice.u16ID = u16ID;
NT35510_SetDisplayDir(pstcLCD, LCD_DISPLAY_VERTICAL);
/* Set cursor */
NT35510_SetCursor(pstcLCD, 0U, 0U);
/* Prepare to write to LCD RAM */
NT35510_PrepareWriteRAM(pstcLCD);
}
}
/**
* @brief Write data on LCD data register.
* @param [in] pstcLCD: LCD controller [url=home.php?mod=space&uid=1064992]@ref[/url] stc_lcd_controller_t structure.
* @param [in] u16Data: Data to be written
* @retval None
*/
void NT35510_WriteData(stc_lcd_controller_t *pstcLCD, uint16_t u16Data)
{
if (NULL != pstcLCD) {
pstcLCD->u16RAM = u16Data;
}
}
/**
* @brief Write register on LCD register.
* @param [in] pstcLCD: LCD controller @ref stc_lcd_controller_t structure.
* @param [in] u16Reg: Address of the selected register.
* @retval None
*/
void NT35510_WriteReg(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg)
{
if (NULL != pstcLCD) {
pstcLCD->u16REG = u16Reg;
}
}
/**
* @brief Read data from LCD data register.
* @param [in] pstcLCD: LCD controller @ref stc_lcd_controller_t structure.
* @retval Read data.
*/
uint16_t NT35510_ReadData(stc_lcd_controller_t *pstcLCD)
{
uint16_t u16Val = 0U;
if (NULL != pstcLCD) {
u16Val = pstcLCD->u16RAM;
}
return u16Val;
}
/**
* @brief Write to the selected LCD register.
* @param [in] pstcLCD: LCD controller @ref stc_lcd_controller_t structure.
* @param [in] u16Reg: Address of the selected register.
* @param [in] u16Data: Data to be written
* @retval None
*/
void NT35510_WriteRegData(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg, uint16_t u16Data)
{
if (NULL != pstcLCD) {
/* Write 16-bit index */
pstcLCD->u16REG = u16Reg;
/* Write 16-bit Reg */
pstcLCD->u16RAM = u16Data;
}
}
/**
* @brief Read the selected LCD register.
* @param [in] pstcLCD: LCD controller @ref stc_lcd_controller_t structure.
* @param [in] u16Reg: Address of the selected register.
* @retval Register value
*/
uint16_t NT35510_ReadRegData(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg)
{
uint16_t u16Val = 0U;
if (NULL != pstcLCD) {
/* Write 16-bit index*/
pstcLCD->u16REG = u16Reg;
u16Val = pstcLCD->u16RAM;
}
return u16Val;
}
/**
* @brief Read LCD ID.
* @param [in] pstcLCD: LCD controller @ref stc_lcd_controller_t structure.
* @retval LCD Register Value.
*/
uint16_t NT35510_ReadID(stc_lcd_controller_t *pstcLCD)
{
uint16_t u16ID = 0U;
if (NULL != pstcLCD) {
/* Try to read ID: 0x9341 */
NT35510_WriteReg(pstcLCD, 0xD3U);
(void)NT35510_ReadData(pstcLCD); /* dummy read */
(void)NT35510_ReadData(pstcLCD); /* read: 0x00 */
u16ID = NT35510_ReadData(pstcLCD) << 8; /* read: 0x93 */
u16ID |= NT35510_ReadData(pstcLCD); /* read: 0x41 */
if (u16ID != 0x9341U) {
/* Try to read ID: 0x8552 */
NT35510_WriteReg(pstcLCD, 0x04U);
(void)NT35510_ReadData(pstcLCD); /* dummy read */
(void)NT35510_ReadData(pstcLCD); /* read: 0x85 */
u16ID = NT35510_ReadData(pstcLCD) << 8; /* read: 0x85 */
u16ID |= NT35510_ReadData(pstcLCD); /* read: 0x41 */
if (u16ID == 0x8552U) {
u16ID = 0x7789U; /* ID convert to: 0x7789 */
} else {
/* Try to read ID: 0x5310 (NT35310) */
NT35510_WriteReg(pstcLCD, 0xD4U);
(void)NT35510_ReadData(pstcLCD); /* dummy read */
(void)NT35510_ReadData(pstcLCD); /* read: 0x01 */
u16ID = NT35510_ReadData(pstcLCD) << 8; /* read: 0x53 */
u16ID |= NT35510_ReadData(pstcLCD); /* read: 0x10 */
if (u16ID != 0x5310U) {
/* Try to read ID: 0x008000 (NT35510) */
NT35510_WriteReg(pstcLCD, 0xDA00);
(void)NT35510_ReadData(pstcLCD); /* read 0xDA00: 0x0000 */
NT35510_WriteReg(pstcLCD, 0xDB00U);
u16ID = NT35510_ReadData(pstcLCD) << 8; /* read 0xDB00: 0x0080 */
NT35510_WriteReg(pstcLCD, 0xDC00U);
u16ID |= NT35510_ReadData(pstcLCD); /* read 0xDC00: 0x0000 */
/* Read ID: ID=008000H (5510H) */
if (u16ID == 0x008000UL) {
u16ID = 0x5510U; /* ID convert to: 0x5510 */
} else {
u16ID = 0U; /* Unsupported LCD */
}
}
}
}
}
return u16ID;
}
/**
* @brief Enable the Display.
* @param [in] pstcLCD: LCD controller
* @retval None
*/
void NT35510_DisplayOn(stc_lcd_controller_t *pstcLCD)
{
if (NULL != pstcLCD) {
if (m_stcLcdDevice.u16ID == 0x5510U) {
NT35510_WriteReg(pstcLCD, 0x2900U); /* 5510 */
} else {
NT35510_WriteReg(pstcLCD, 0x29U); /* 9341/5310/1963/7789 */
}
}
}
/**
* @brief Disable the Display.
* @param [in] pstcLCD: LCD controller
* @retval None
*/
void NT35510_DisplayOff(stc_lcd_controller_t *pstcLCD)
{
if (NULL != pstcLCD) {
if (m_stcLcdDevice.u16ID == 0x5510U) {
NT35510_WriteReg(pstcLCD, 0x2800U); /* 5510 */
} else {
NT35510_WriteReg(pstcLCD, 0x28U); /* 9341/5310/1963/7789 */
}
}
}
/**
* @brief Get LCD PIXEL WIDTH.
* @param None
* @retval LCD PIXEL WIDTH.
*/
uint16_t NT35510_GetPixelWidth(void)
{
return m_stcLcdDevice.u16Width;
}
/**
* @brief Get LCD PIXEL HEIGHT.
* @param None
* @retval LCD PIXEL HEIGHT.
*/
uint16_t NT35510_GetPixelHeight(void)
{
return m_stcLcdDevice.u16Height;
}
/**
* @brief Set scan direction.
* @param [in] pstcLCD: LCD controller
* @param [in] u16Dir: Scan direction
* This parameter can be one of the following values:
* [url=home.php?mod=space&uid=1238002]@arg[/url] LCD_SCAN_DIR_L2R_U2D: From left to right && from up to down
* @arg LCD_SCAN_DIR_L2R_D2U: From left to right && from down to up
* @arg LCD_SCAN_DIR_R2L_U2D: From right to left && from up to down
* @arg LCD_SCAN_DIR_R2L_D2U: From right to left && from down to up
* @arg LCD_SCAN_DIR_U2D_L2R: From up to down && from left to right
* @arg LCD_SCAN_DIR_U2D_R2L: From up to down && from right to left
* @arg LCD_SCAN_DIR_D2U_L2R: From down to up && from left to right
* @arg LCD_SCAN_DIR_D2U_R2L: From down to up && from right to left
* @retval None
*/
void NT35510_SetScanDir(stc_lcd_controller_t *pstcLCD, uint16_t u16Dir)
{
uint16_t u16Temp;
uint16_t dirreg;
uint16_t regval = 0U;
if (NULL != pstcLCD) {
/* when display dir is VERTICAL, 1963 IC change scan-direction, other IC don't change
when display dir is HORIZONTAL, 1963 IC don't change scan-direction, other IC change */
if (((0U == m_stcLcdDevice.u16Dir) && (m_stcLcdDevice.u16ID == 0x1963U)) || \
((1U == m_stcLcdDevice.u16Dir) && (m_stcLcdDevice.u16ID != 0x1963U))) {
if (0U == u16Dir) {
u16Dir = 6U;
} else if (1U == u16Dir) {
u16Dir = 7U;
} else if (2U == u16Dir) {
u16Dir = 4U;
} else if (3UL == u16Dir) {
u16Dir = 5U;
} else if (4U == u16Dir) {
u16Dir = 1U;
} else if (5U == u16Dir) {
u16Dir = 0U;
} else if (6U == u16Dir) {
u16Dir = 3U;
} else if (7U == u16Dir) {
u16Dir = 2U;
} else {
u16Dir = 6U;
}
}
switch (u16Dir) {
case LCD_SCAN_DIR_L2R_U2D:
regval |= ((0U << 7) | (0U << 6) | (0U << 5));
break;
case LCD_SCAN_DIR_L2R_D2U:
regval |= ((1U << 7) | (0U << 6) | (0U << 5));
break;
case LCD_SCAN_DIR_R2L_U2D:
regval |= ((0U << 7) | (1U << 6) | (0U << 5));
break;
case LCD_SCAN_DIR_R2L_D2U:
regval |= ((1U << 7) | (1U << 6) | (0U << 5));
break;
case LCD_SCAN_DIR_U2D_L2R:
regval |= ((0U << 7) | (0U << 6) | (1U << 5));
break;
case LCD_SCAN_DIR_U2D_R2L:
regval |= ((0U << 7) | (1U << 6) | (1U << 5));
break;
case LCD_SCAN_DIR_D2U_L2R:
regval |= ((1U << 7) | (0U << 6) | (1U << 5));
break;
case LCD_SCAN_DIR_D2U_R2L:
regval |= ((1U << 7) | (1U << 6) | (1U << 5));
break;
default:
break;
}
if (0x5510U == m_stcLcdDevice.u16ID) {
dirreg = 0x3600U;
} else {
dirreg = 0x36U;
}
/* 0x9341 & 0x7789 set BGR bit */
if ((0x9341U == m_stcLcdDevice.u16ID) || (0x7789U == m_stcLcdDevice.u16ID)) {
regval |= 0x08U;
}
NT35510_WriteRegData(pstcLCD, dirreg, regval);
/* 1963 don't handle coordinate */
if (m_stcLcdDevice.u16ID != 0x1963U) {
if ((regval & 0x20U) > 0U) {
/* swap X,Y */
if (m_stcLcdDevice.u16Width < m_stcLcdDevice.u16Height) {
u16Temp = m_stcLcdDevice.u16Width;
m_stcLcdDevice.u16Width = m_stcLcdDevice.u16Height;
m_stcLcdDevice.u16Height = u16Temp;
}
} else {
/* swap X,Y */
if (m_stcLcdDevice.u16Width > m_stcLcdDevice.u16Height) {
u16Temp = m_stcLcdDevice.u16Width;
m_stcLcdDevice.u16Width = m_stcLcdDevice.u16Height;
m_stcLcdDevice.u16Height = u16Temp;
}
}
}
/* Set display window size */
if (0x5510U == m_stcLcdDevice.u16ID) {
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd + 1U);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd + 2U);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) >> 8U);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd + 3U);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) & 0xFFU);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd + 1U);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd + 2U);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) >> 8U);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd + 3U);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) & 0xFFU);
} else {
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) >> 8);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) & 0xFFU);
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) >> 8);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) & 0xFFU);
}
}
}
/**
* @brief Set screen direction.
* @param [in] pstcLCD: LCD controller
* @param [in] u16Dir: Screen direction
* This parameter can be one of the following values:
* @arg LCD_DISPLAY_VERTICAL: LCD vertical display
* @arg LCD_DISPLAY_HORIZONTAL: LCD horizontal display
* @retval None
*/
void NT35510_SetDisplayDir(stc_lcd_controller_t *pstcLCD, uint16_t u16Dir)
{
if (NULL != pstcLCD) {
if (LCD_DISPLAY_VERTICAL == u16Dir) { /* Vertical */
if (0x1963U == m_stcLcdDevice.u16ID) {
m_stcLcdDevice.u16WRamCmd = 0x2CU;
m_stcLcdDevice.u16SetXCmd = 0x2BU;
m_stcLcdDevice.u16SetYCmd = 0x2AU;
m_stcLcdDevice.u16Width = 480U;
m_stcLcdDevice.u16Height = 800U;
} else if (0x5510U == m_stcLcdDevice.u16ID) {
/* NT35510 */
m_stcLcdDevice.u16WRamCmd = 0x2C00U;
m_stcLcdDevice.u16SetXCmd = 0x2A00U;
m_stcLcdDevice.u16SetYCmd = 0x2B00U;
m_stcLcdDevice.u16Width = 480U;
m_stcLcdDevice.u16Height = 800U;
} else {
/* NT35310 / 9341 / 5310 / 7789 etc */
m_stcLcdDevice.u16WRamCmd = 0x2CU;
m_stcLcdDevice.u16SetXCmd = 0x2AU;
m_stcLcdDevice.u16SetYCmd = 0x2BU;
if (0x5310U == m_stcLcdDevice.u16ID) {
/* NT35310 */
m_stcLcdDevice.u16Width = 320U;
m_stcLcdDevice.u16Height = 480U;
} else {
m_stcLcdDevice.u16Width = 240U;
m_stcLcdDevice.u16Height = 320U;
}
}
} else { /* Horizontal */
if (0x1963U == m_stcLcdDevice.u16ID) {
m_stcLcdDevice.u16WRamCmd = 0x2CU;
m_stcLcdDevice.u16SetXCmd = 0x2AU;
m_stcLcdDevice.u16SetYCmd = 0x2BU;
m_stcLcdDevice.u16Width = 800U;
m_stcLcdDevice.u16Height = 480U;
} else if (0x5510U == m_stcLcdDevice.u16ID) {
/* NT35510 */
m_stcLcdDevice.u16WRamCmd = 0x2C00U;
m_stcLcdDevice.u16SetXCmd = 0x2A00U;
m_stcLcdDevice.u16SetYCmd = 0x2B00U;
m_stcLcdDevice.u16Width = 800U;
m_stcLcdDevice.u16Height = 480U;
} else {
/* NT35310 / 9341 / 5310 / 7789 etc */
m_stcLcdDevice.u16WRamCmd = 0x2CU;
m_stcLcdDevice.u16SetXCmd = 0x2AU;
m_stcLcdDevice.u16SetYCmd = 0x2BU;
if (0x5310U == m_stcLcdDevice.u16ID) {
/* NT35310 */
m_stcLcdDevice.u16Width = 480U;
m_stcLcdDevice.u16Height = 320U;
} else {
m_stcLcdDevice.u16Width = 320U;
m_stcLcdDevice.u16Height = 240U;
}
}
}
m_stcLcdDevice.u16Dir = u16Dir;
NT35510_SetScanDir(pstcLCD, LCD_SCAN_DIR);
}
}
/**
* @brief Prepare to write LCD RAM.
* @param [in] pstcLCD: LCD controller
* @retval None
*/
void NT35510_PrepareWriteRAM(stc_lcd_controller_t *pstcLCD)
{
if (NULL != pstcLCD) {
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16WRamCmd);
}
}
/**
* @brief Set screen backlight.
* @param [in] pstcLCD: LCD controller
* @param [in] u8PWM: PWM level
This parameter can be a value between Min_Data = 0 and Max_Data = 100
* @retval None
*/
void NT35510_SetBackLight(stc_lcd_controller_t *pstcLCD, uint8_t u8PWM)
{
float32_t f32PWM = ((float32_t)u8PWM * 2.55F);
if (NULL != pstcLCD) {
NT35510_WriteReg(pstcLCD, 0xBEU);
NT35510_WriteData(pstcLCD, 0x05U);
NT35510_WriteData(pstcLCD, (uint16_t)f32PWM);
NT35510_WriteData(pstcLCD, 0x01U);
NT35510_WriteData(pstcLCD, 0xFFU);
NT35510_WriteData(pstcLCD, 0x00U);
NT35510_WriteData(pstcLCD, 0x00U);
}
}
/**
* @brief Set Cursor position.
* @param [in] pstcLCD: LCD controller
* @param u16Xpos: Specifies the X position.
* @param u16Ypos: Specifies the Y position.
* @retval None
*/
void NT35510_SetCursor(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos)
{
if (NULL != pstcLCD) {
if (0x1963U == m_stcLcdDevice.u16ID) {
/* Convert X coordinate */
if (m_stcLcdDevice.u16Dir == 0U) {
u16Xpos = m_stcLcdDevice.u16Width - 1U - u16Xpos;
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteData(pstcLCD, 0U);
NT35510_WriteData(pstcLCD, u16Xpos >> 8);
NT35510_WriteData(pstcLCD, u16Xpos & 0xFFU);
} else {
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd);
NT35510_WriteData(pstcLCD, u16Xpos >> 8);
NT35510_WriteData(pstcLCD, u16Xpos & 0xFFU);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) >> 8);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) & 0xFFU);
}
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
NT35510_WriteData(pstcLCD, u16Ypos >> 8);
NT35510_WriteData(pstcLCD, u16Ypos & 0xFFU);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) >> 8);
NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) & 0xFFU);
} else if (0x5510U == m_stcLcdDevice.u16ID) {
NT35510_WriteRegData(pstcLCD, m_stcLcdDevice.u16SetXCmd, (u16Xpos >> 8U));
NT35510_WriteRegData(pstcLCD, (m_stcLcdDevice.u16SetXCmd + 1U), (u16Xpos & 0xFFU));
NT35510_WriteRegData(pstcLCD, m_stcLcdDevice.u16SetYCmd, (u16Ypos >> 8U));
NT35510_WriteRegData(pstcLCD, (m_stcLcdDevice.u16SetYCmd + 1U), (u16Ypos & 0xFFU));
} else { /* NT35310 / 9341 / 5310 / 7789 etc */
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd);
NT35510_WriteData(pstcLCD, (u16Xpos >> 8));
NT35510_WriteData(pstcLCD, (u16Xpos & 0xFFU));
NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
NT35510_WriteData(pstcLCD, (u16Ypos >> 8));
NT35510_WriteData(pstcLCD, (u16Ypos & 0xFFU));
}
}
}
/**
* @brief Write pixel.
* @param [in] pstcLCD: LCD controller
* @param u16Xpos: Specifies the X position.
* @param u16Ypos: Specifies the Y position.
* @param u16RGBCode: The RGB pixel color in RGB565 format
* @retval None
*/
void NT35510_WritePixel(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos, uint16_t u16RGBCode)
{
if (NULL != pstcLCD) {
/* Set cursor */
NT35510_SetCursor(pstcLCD, u16Xpos, u16Ypos);
/* Prepare to write to LCD RAM */
NT35510_PrepareWriteRAM(pstcLCD);
NT35510_WriteData(pstcLCD, u16RGBCode);
}
}
/**
* @brief Draw line.
* @param [in] pstcLCD: LCD controller
* @param u16X1: Specifies the X position 1.
* @param u16X2: Specifies the X position 2.
* @param u16Y1: Specifies the Y position 1.
* @param u16Y2: Specifies the Y position 2.
* @param u16RGBCode: The RGB pixel color in RGB565 format
* @retval None
*/
void NT35510_DrawLine(stc_lcd_controller_t *pstcLCD, uint16_t u16X1, uint16_t u16Y1,
uint16_t u16X2, uint16_t u16Y2, uint16_t u16RGBCode)
{
int16_t t;
int16_t xerr = 0;
int16_t yerr = 0;
int16_t delta_x;
int16_t delta_y;
int16_t distance;
int16_t incx;
int16_t incy;
int16_t Row;
int16_t Col;
if (NULL != pstcLCD) {
Row = (int16_t)u16X1;
Col = (int16_t)u16Y1;
delta_x = ((int16_t)u16X2 - (int16_t)u16X1); /* calc delta X, Y*/
delta_y = ((int16_t)u16Y2 - (int16_t)u16Y1);
if (delta_x > 0) {
incx = 1; /* forward u8Direction */
} else if (delta_x == 0) {
incx = 0; /* vertical line */
} else {
incx = -1; /* reverse direction */
delta_x = -delta_x;
}
if (delta_y > 0) {
incy = 1; /* downward direction */
} else if (delta_y == 0) {
incy = 0; /* horizontal line */
} else {
incy = -1; /* upward direction */
delta_y = -delta_y;
}
if (delta_x > delta_y) {
distance = delta_x; /* set axis */
} else {
distance = delta_y;
}
for (t = 0; t <= (distance + 1); t++) {
NT35510_WritePixel(pstcLCD, (uint16_t)Row, (uint16_t)Col, u16RGBCode); /* draw pixel */
xerr += delta_x ;
yerr += delta_y ;
if (xerr > distance) {
xerr -= distance;
Row += incx;
}
if (yerr > distance) {
yerr -= distance;
Col += incy;
}
}
}
}
/**
* @brief Draw a circle.
* @param [in] pstcLCD: LCD controller
* @param [in] u16Xpos: X position
* @param [in] u16Ypos: Y position
* @param [in] u16Radius: Circle radius
* @param u16RGBCode: The RGB pixel color in RGB565 format
* @retval None
*/
void NT35510_DrawCircle(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos,
uint16_t u16Radius, uint16_t u16RGBCode)
{
int32_t decision; /* Decision Variable */
uint32_t current_x; /* Current X Value */
uint32_t current_y; /* Current Y Value */
if (NULL != pstcLCD) {
decision = 3 - ((int32_t)u16Radius * 2);
current_x = 0U;
current_y = u16Radius;
while (current_x <= current_y) {
NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_x), (u16Ypos - (uint16_t)current_y), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_y), (u16Ypos - (uint16_t)current_x), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_y), (u16Ypos + (uint16_t)current_x), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_x), (u16Ypos + (uint16_t)current_y), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_x), (u16Ypos + (uint16_t)current_y), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_y), (u16Ypos + (uint16_t)current_x), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_x), (u16Ypos - (uint16_t)current_y), u16RGBCode);
NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_y), (u16Ypos - (uint16_t)current_x), u16RGBCode);
current_x++;
/* Bresenham algorithm */
if (decision < 0) {
decision += ((4 * (int32_t)current_x) + 6);
} else {
decision += (10 + (4 * ((int32_t)current_x - (int32_t)current_y)));
current_y--;
}
}
}
}
/**
* @brief Fill a triangle (between 3 points).
* @param [in] pstcLCD: LCD controller
* @param [in] u16X1: Point 1 X position
* @param [in] u16Y1: Point 1 Y position
* @param [in] u16X2: Point 2 X position
* @param [in] u16Y2: Point 2 Y position
* @param [in] u16X3: Point 3 X position
* @param [in] u16Y3: Point 3 Y position
* @param u16RGBCode: The RGB pixel color in RGB565 format
* @retval None
*/
void NT35510_FillTriangle(stc_lcd_controller_t *pstcLCD, uint16_t u16X1, uint16_t u16Y1,
uint16_t u16X2, uint16_t u16Y2, uint16_t u16X3, uint16_t u16Y3, uint16_t u16RGBCode)
{
uint16_t deltax;
uint16_t deltay;
int16_t xoff;
int16_t yoff;
int16_t xinc1;
int16_t xinc2;
int16_t yinc1;
int16_t yinc2;
uint16_t den;
uint16_t num;
uint16_t numadd;
uint16_t numpixels;
uint16_t curpixel;
if (NULL != pstcLCD) {
xoff = (int16_t)u16X1; /* Start x off at the first pixel */
yoff = (int16_t)u16Y1; /* Start y off at the first pixel */
/* The difference between the x's */
if (u16X2 > u16X1) {
deltax = (u16X2 - u16X1);
} else {
deltax = (u16X1 - u16X2);
}
/* The difference between the y's */
if (u16Y2 > u16Y1) {
deltay = (u16Y2 - u16Y1);
} else {
deltay = (u16Y1 - u16Y2);
}
if (u16X2 >= u16X1) {
/* The x-values are increasing */
xinc1 = 1;
xinc2 = 1;
} else {
/* The x-values are decreasing */
xinc1 = -1;
xinc2 = -1;
}
if (u16Y2 >= u16Y1) {
/* The y-values are increasing */
yinc1 = 1;
yinc2 = 1;
} else {
/* The y-values are decreasing */
yinc1 = -1;
yinc2 = -1;
}
/* There is at least one x-value for every y-value */
if (deltax >= deltay) {
xinc1 = 0; /* Don't change the x when numerator >= denominator */
yinc2 = 0; /* Don't change the y for every iteration */
den = deltax;
num = (deltax / 2U);
numadd = deltay;
numpixels = deltax; /* There are more x-values than y-values */
} else {
/* There is at least one y-value for every x-value */
xinc2 = 0; /* Don't change the x for every iteration */
yinc1 = 0; /* Don't change the y when numerator >= denominator */
den = deltay;
num = (deltay / 2U);
numadd = deltax;
numpixels = deltay; /* There are more y-values than x-values */
}
for (curpixel = 0U; curpixel <= numpixels; curpixel++) {
NT35510_DrawLine(pstcLCD, (uint16_t)xoff, (uint16_t)yoff, u16X3, u16Y3, u16RGBCode);
num += numadd; /* Increase the numerator by the top of the fraction */
/* Check if numerator >= denominator */
if (num >= den) {
num -= den; /* Calculate the new numerator value */
xoff += xinc1; /* Change the x as appropriate */
yoff += yinc1; /* Change the y as appropriate */
}
xoff += xinc2; /* Change the x as appropriate */
yoff += yinc2; /* Change the y as appropriate */
}
}
}
/**
* @brief Draw rectangle.
* @param [in] pstcLCD: LCD controller
* @param [in] u16X1: Point 1 X position
* @param [in] u16Y1: Point 1 Y position
* @param [in] u16X2: Point 2 X position
* @param [in] u16Y2: Point 2 Y position
* @param u16RGBCode: The RGB pixel color in RGB565 format
* @retval None
*/
void NT35510_DrawRectangle(stc_lcd_controller_t *pstcLCD, uint16_t u16X1, uint16_t u16Y1,
uint16_t u16X2, uint16_t u16Y2, uint16_t u16RGBCode)
{
if (NULL != pstcLCD) {
NT35510_DrawLine(pstcLCD, u16X1, u16Y1, u16X2, u16Y1, u16RGBCode);
NT35510_DrawLine(pstcLCD, u16X1, u16Y1, u16X1, u16Y2, u16RGBCode);
NT35510_DrawLine(pstcLCD, u16X1, u16Y2, u16X2, u16Y2, u16RGBCode);
NT35510_DrawLine(pstcLCD, u16X2, u16Y1, u16X2, u16Y2, u16RGBCode);
}
}
/**
* @brief Clear screen.
* @param [in] pstcLCD: LCD controller
* @param u16RGBCode: The RGB pixel color in RGB565 format
* @retval None
*/
void NT35510_Clear(stc_lcd_controller_t *pstcLCD, uint16_t u16RGBCode)
{
uint32_t i;
uint32_t u32TotalPoint;
if (NULL != pstcLCD) {
/* Set cursor */
NT35510_SetCursor(pstcLCD, 0U, 0U);
/* Prepare to write to LCD RAM */
NT35510_PrepareWriteRAM(pstcLCD);
u32TotalPoint = (uint32_t)m_stcLcdDevice.u16Width * (uint32_t)m_stcLcdDevice.u16Height;
for (i = 0UL; i < u32TotalPoint; i++) {
NT35510_WriteData(pstcLCD, u16RGBCode);
}
}
}
基于硬件I2C的触摸驱动实现:
/**
* @brief Read register on touch pad register.
* @param [in] pstcGt9xxLL Pointer to a @ref stc_gt9xx_ll_t structure
* @param [in] u16Reg Register to be read
* @param [out] pu8RegValue The buffer for reading
* @param [in] u32Len The buffer size for bytes
* @retval None
*/
void GT9XX_REG_Read(const stc_gt9xx_ll_t *pstcGt9xxLL, uint16_t u16Reg, uint8_t *pu8RegValue, uint32_t u32Len)
{
uint8_t au8RegAddr[2];
if ((NULL != pstcGt9xxLL) && (NULL != pstcGt9xxLL->Read) && (NULL != pu8RegValue)) {
au8RegAddr[0] = (uint8_t)((u16Reg & 0xFF00U) >> 8);
au8RegAddr[1] = (uint8_t)(u16Reg & 0x00FFU);
(void)pstcGt9xxLL->Read(au8RegAddr, ARRAY_SZ(au8RegAddr), pu8RegValue, u32Len);
}
}
/**
* @brief Write register on touch pad register.
* @param [in] pstcGt9xxLL Pointer to a @ref stc_gt9xx_ll_t structure
* @param [in] u16Reg Register to be write
* @param [in] pu8RegValue The buffer for writing
* @param [in] u32Len The buffer size for bytes
* @retval None
*/
void GT9XX_REG_Write(const stc_gt9xx_ll_t *pstcGt9xxLL, uint16_t u16Reg, const uint8_t *pu8RegValue, uint32_t u32Len)
{
uint8_t au8RegAddr[2];
if ((NULL != pstcGt9xxLL) && (NULL != pstcGt9xxLL->Write) && (NULL != pu8RegValue)) {
au8RegAddr[0] = (uint8_t)((u16Reg & 0xFF00U) >> 8);
au8RegAddr[1] = (uint8_t)(u16Reg & 0x00FFU);
(void)pstcGt9xxLL->Write(au8RegAddr, ARRAY_SZ(au8RegAddr), pu8RegValue, u32Len);
}
}
/**
* @brief Reset GT9XX.
* @param [in] pstcGt9xxLL Pointer to a @ref stc_gt9xx_ll_t structure.
* @retval None
*/
void GT9XX_SoftReset(const stc_gt9xx_ll_t *pstcGt9xxLL)
{
uint8_t u8RegValue = 0x02U;
GT9XX_REG_Write(pstcGt9xxLL, GT9XX_COMMAND, &u8RegValue, 1UL);
}
/**
* @brief Read GT9XX touch status.
* @param [in] pstcGt9xxLL Pointer to a @ref stc_gt9xx_ll_t structure.
* @retval Touch status
*/
uint8_t GT9XX_ReadTouchStatus(const stc_gt9xx_ll_t *pstcGt9xxLL)
{
uint8_t u8Status = 0U;
GT9XX_REG_Read(pstcGt9xxLL, GT9XX_TOUCH_STATUS, &u8Status, 1UL);
return u8Status;
}
/**
* @brief Read GT9XX ID.
* @param [in] pstcGt9xxLL Pointer to a @ref stc_gt9xx_ll_t structure.
* @param [out] pu8IDValue The buffer for reading ID
* @param [in] u32Len The buffer size for bytes
* @retval None
*/
void GT9XX_ReadProductID(const stc_gt9xx_ll_t *pstcGt9xxLL, uint8_t *pu8IDValue, uint32_t u32Len)
{
GT9XX_REG_Read(pstcGt9xxLL, GT9XX_PRODUCT_ID, pu8IDValue, u32Len);
}
/**
* @brief Read GT9XX point.
* @param [in] pstcGt9xxLL Pointer to a @ref stc_gt9xx_ll_t structure.
* @param [in] u16Point Touch pad point
* @param [out] pu16X Point x coordinate
* @param [out] pu16Y Point y coordinate
* @retval None
*/
void GT9XX_GetXY(const stc_gt9xx_ll_t *pstcGt9xxLL, uint16_t u16Point, uint16_t *pu16X, uint16_t *pu16Y)
{
uint8_t au8Tmp[4];
if ((pu16X != NULL) && (pu16Y != NULL)) {
GT9XX_REG_Read(pstcGt9xxLL, u16Point, au8Tmp, 4UL);
(*pu16X) = (uint16_t)au8Tmp[0] | ((uint16_t)au8Tmp[1] << 8);
(*pu16Y) = (uint16_t)au8Tmp[2] | ((uint16_t)au8Tmp[3] << 8);
}
}
主程序:
/**
* @brief BSP clock initialize.
* SET board system clock to PLLH@160MHz
* Flash: 3 wait
* SRAM_H: 0 wait
* SRAM_B: 1 wait
* PCLK0: 160MHz
* PCLK1: 80MHz
* PCLK2: 40MHz
* PCLK3: 40MHz
* PCLK4: 80MHz
* EXCLK: 40MHz
* HCLK: 160MHz
* @param None
* @retval None
*/
void BSP_CLK_Init(void)
{
stc_clock_xtal_init_t stcXtalInit;
stc_clock_pll_init_t stcPLLHInit;
/* PCLK0, HCLK Max 200MHz */
/* PCLK1, PCLK4 Max 100MHz */
/* PCLK2, EXCLK Max 60MHz */
/* PCLK3 Max 50MHz */
CLK_SetClockDiv(CLK_BUS_CLK_ALL,
(CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 |
CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV4 |
CLK_HCLK_DIV1));
GPIO_AnalogCmd(BSP_XTAL_PORT, BSP_XTAL_IN_PIN | BSP_XTAL_OUT_PIN, ENABLE);
(void)CLK_XtalStructInit(&stcXtalInit);
/* Config Xtal and enable Xtal */
stcXtalInit.u8Mode = CLK_XTAL_MD_OSC;
stcXtalInit.u8Drv = CLK_XTAL_DRV_ULOW;
stcXtalInit.u8State = CLK_XTAL_ON;
stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;
(void)CLK_XtalInit(&stcXtalInit);
(void)CLK_PLLStructInit(&stcPLLHInit);
/* VCO = (8/1)*800 = 640MHz*/
stcPLLHInit.u8PLLState = CLK_PLL_ON;
stcPLLHInit.PLLCFGR = 0UL;
stcPLLHInit.PLLCFGR_f.PLLM = 1UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLN = 80UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLP = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLQ = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLR = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL;
(void)CLK_PLLInit(&stcPLLHInit);
/* 3 cycles for 150 ~ 200MHz */
(void)EFM_SetWaitCycle(EFM_WAIT_CYCLE3);
/* 3 cycles for 150 ~ 200MHz */
GPIO_SetReadWaitCycle(GPIO_RD_WAIT3);
CLK_SetSysClockSrc(CLK_SYSCLK_SRC_PLL);
}
/**
* @brief Return true is the touchpad is pressed
* @param None
* @retval Press state
*/
static bool TOUCHPAD_IsPressed(void)
{
uint8_t u8Tmp;
uint8_t u8Status;
bool bPressed = false;
BSP_GT9XX_REG_Read(GT9XX_TOUCH_STATUS, &u8Status, 1UL);
if ((u8Status & 0x80U) != 0U) {
u8Tmp = 0U;
BSP_GT9XX_REG_Write(GT9XX_TOUCH_STATUS, &u8Tmp, 1U);
if ((0U < (u8Status & 0x0FU)) && ((u8Status & 0x0FU) < 6U)) {
bPressed = true;
}
}
return bPressed;
}
/**
* @brief Get touch data.
* @param [out] pstcData Pointer to a @ref stc_touchpad_data_t structure.
* @retval None
*/
static void TOUCHPAD_Read(stc_touchpad_data_t *pstcData)
{
static uint16_t u16LastX = 0U;
static uint16_t u16LastY = 0U;
/*Save the pressed coordinates and the state*/
if (TOUCHPAD_IsPressed()) {
BSP_GT9XX_GetXY(GT9XX_POINT1, &u16LastX, &u16LastY);
pstcData->enPointPress = SET;
} else {
pstcData->enPointPress = RESET;
}
/*Set the last pressed coordinates*/
pstcData->stcPoint.u16X = u16LastX;
pstcData->stcPoint.u16Y = u16LastY;
}
/**
* @brief Check if a point is on an window
* @param [in] pstcWin Pointer to a @ref stc_touchpad_window_t structure.
* @param [in] pstcPoint Pointer to a @ref stc_touchpad_point_t structure.
* @retval bool:
* - true: The point is in the area.
* - false: The point is out the area.
*/
bool TOUCHPAD_IsPointOn(const stc_touchpad_window_t *pstcWin, const stc_touchpad_point_t *pstcPoint)
{
bool bIsPointOnWin = false;
if ((pstcPoint->u16X >= pstcWin->u16X1 && pstcPoint->u16X <= pstcWin->u16X2) && \
(pstcPoint->u16Y >= pstcWin->u16Y1 && pstcPoint->u16Y <= pstcWin->u16Y2)) {
bIsPointOnWin = true;
}
return bIsPointOnWin;
}
/**
* @brief Main function of LCD project
* @param None
* @retval int32_t return value, if needed
*/
int32_t main(void)
{
uint8_t i;
uint16_t u16Width;
uint16_t u16Height;
bool bIsPointOnWin;
const uint8_t u8RectangleCount = 3U;
uint16_t u16WinSize;
stc_touchpad_window_t stcWin;
/* MCU Peripheral registers write unprotected */
LL_PERIPH_WE(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_EFM);
/* Initialize system clock: */
BSP_CLK_Init();
BSP_IO_Init();
BSP_LCD_IO_Init();
/* Initialize LCD touch pad */
BSP_GT9XX_Init();
/* HW Reset LCD */
BSP_LCD_RSTCmd(EIO_PIN_RESET); /* RST# to low */
DDL_DelayMS(50UL);
BSP_LCD_RSTCmd(EIO_PIN_SET); /* RST# to high */
DDL_DelayMS(50UL);
/* Initialize NT35510 LCD */
BSP_NT35510_Init();
/* Clear LCD screen */
BSP_NT35510_Clear(LCD_COLOR_BLACK);
/* Turn on LCD backlight */
BSP_LCD_BKLCmd(EIO_PIN_SET);
/* Set LCD cursor */
BSP_NT35510_SetCursor(0U, 0U);
/* MCU Peripheral registers write protected */
LL_PERIPH_WP(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_EFM);
u16Width = BSP_NT35510_GetPixelWidth();
u16Height = BSP_NT35510_GetPixelHeight();
for (;;) {
for (i = 0U; i < u8RectangleCount; i++) {
bIsPointOnWin = false;
u16WinSize = u16Width / u8RectangleCount;
stcWin.u16X1 = (i * u16WinSize);
stcWin.u16Y1 = (u16Height / 2U) - (u16WinSize / 2U);
stcWin.u16X2 = stcWin.u16X1 + u16WinSize - 1U;
stcWin.u16Y2 = (u16Height / 2U) + (u16WinSize / 2U) - 1U;
BSP_NT35510_DrawRectangle(stcWin.u16X1, stcWin.u16Y1, stcWin.u16X2, stcWin.u16Y2, LCD_COLOR_GREEN);
do {
(void)memset(&m_stcTouchData, 0, sizeof(m_stcTouchData));
TOUCHPAD_Read(&m_stcTouchData);
if (m_stcTouchData.enPointPress == SET) {
bIsPointOnWin = TOUCHPAD_IsPointOn(&stcWin, &m_stcTouchData.stcPoint);
}
} while (false == bIsPointOnWin);
BSP_NT35510_Clear(LCD_COLOR_BLACK);
}
BSP_NT35510_DrawCircle(u16Width / 2U, u16Height / 2U, u16Width / 4U, LCD_COLOR_RED);
DDL_DelayMS(1000UL);
BSP_NT35510_Clear(LCD_COLOR_RED);
DDL_DelayMS(1000UL);
BSP_NT35510_Clear(LCD_COLOR_GREEN);
DDL_DelayMS(1000UL);
BSP_NT35510_Clear(LCD_COLOR_BLUE);
DDL_DelayMS(1000UL);
/* Clear LCD screen */
BSP_NT35510_Clear(LCD_COLOR_BLACK);
}
}
6.运行效果
注意事项:拨码开关SW2选择EXMC功能 & 码开关SW4选择LCD功!
[localvideo]865b7898a142bdd8191184d2e77f3d5f[/localvideo]
- 2024-02-19
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】02.熟悉CAN通讯(邮箱、ID过滤等),与PC通讯测试
本帖最后由 xld0932 于 2024-2-19 11:32 编辑
1.概述
当前CAN通讯应用越来越广泛、汽车电子、工业控制,到近些年的电动车,都开始使用CAN组网通讯了,这都得益于CAN的高效、稳定和规范。国民技术N32A455系列MCU带有2组CAN通讯接口,最高波特率可达到1Mbit/s,支持CAN协议2.0A和2.0B,支持时间触发通讯功能;每个CAN都有两个3级深度的接收FIFO、共有14个过滤器组、3个发送邮箱,通过接收FIFO和过滤机制,降低了CAN消息的实时响应要求,减少MCU不必要的消耗,同时也提升了MCU的利用率。
2.熟悉CAN模块
2.1.工作模式
初始化、正常和睡眠模式是CAN的三种主要工作模式。软件只有在CAN处于初始化模式时才能进行初始化配置、在初始化完成后,软件配置CAN进入正常模式、通过配置寄存器相应位可以使CAN进入睡眠模式,在进入睡眠模式后,可以通过硬件自动唤醒(检测到CAN总线的活动),也可以通过软件唤醒(操作寄存器位),需要注意的是在进入正常模式之前,CAN必须与CAN总线同步。另外还有测试模式(回环模式、静默模式、回环静默模式)、调试模式。
2.2.发送邮箱
应用程序可以通过三个发送邮箱发送消息,发送三个邮箱消息的顺序是由发送调度器根据消息的优先级决定的,优先级可以由消息的标识符决定,也可以由发送请求的顺序决定。
2.3.接收过滤器
每个 CAN 有 14 个可配置的标识符过滤器组。应用配置标识符过滤器组后,接收邮箱会自动接收需要的邮件,丢弃其他邮件。
2.4.接收FIFO
每个 CAN 有两个接收 FIFO,每个 FIFO 可以存储三个完整的报文。无需应用程序管理,由硬件管理。
3.CAN通讯示例
3.1.GPIO初始化配置
/* PD8_CAN1_RX */
#define CAN1_RX_RCC RCC_APB2_PERIPH_GPIOD
#define CAN1_RX_GPIO GPIOD
#define CAN1_RX_PIN GPIO_PIN_8
/* PD9_CAN1_TX */
#define CAN1_TX_RCC RCC_APB2_PERIPH_GPIOD
#define CAN1_TX_GPIO GPIOD
#define CAN1_TX_PIN GPIO_PIN_9
/* PE0_CAN1_STB */
#define CAN1_STB_RCC RCC_APB2_PERIPH_GPIOE
#define CAN1_STB_GPIO GPIOE
#define CAN1_STB_PIN GPIO_PIN_0
void CAN_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_EnableAPB2PeriphClk(CAN1_RX_RCC | RCC_APB2_PERIPH_AFIO, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = CAN1_RX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitPeripheral(CAN1_RX_GPIO, &GPIO_InitStructure);
RCC_EnableAPB2PeriphClk(CAN1_TX_RCC | RCC_APB2_PERIPH_AFIO, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = CAN1_TX_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitPeripheral(CAN1_TX_GPIO, &GPIO_InitStructure);
RCC_EnableAPB2PeriphClk(CAN1_STB_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = CAN1_STB_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(CAN1_STB_GPIO, &GPIO_InitStructure);
GPIO_WriteBit(CAN1_STB_GPIO, CAN1_STB_PIN, Bit_RESET);
GPIO_ConfigPinRemap(GPIO_RMP1_CAN1, ENABLE);
......
}
3.2.CAN通讯参数配置
void CAN_Configuration(void)
{
......
CAN_InitType CAN_InitStructure;
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_CAN1, ENABLE);
CAN_DeInit(CAN1);
CAN_InitStruct(&CAN_InitStructure);
CAN_InitStructure.TTCM = DISABLE;
CAN_InitStructure.ABOM = DISABLE;
CAN_InitStructure.AWKUM = DISABLE;
CAN_InitStructure.NART = DISABLE;
CAN_InitStructure.RFLM = DISABLE;
CAN_InitStructure.TXFP = ENABLE;
CAN_InitStructure.OperatingMode = CAN_Normal_Mode;
CAN_InitStructure.RSJW = CAN_RSJW_1tq;
CAN_InitStructure.TBS1 = CAN_TBS1_14tq;
CAN_InitStructure.TBS2 = CAN_TBS2_3tq;
CAN_InitStructure.BaudRatePrescaler = 4;
CAN_Init(CAN1, &CAN_InitStructure);
......
}
3.3.CAN过滤器配置
#define CAN_FILTER_STDID(STDID) ((STDID & 0x7FF) << 5)
#define CAN_FILTER_EXTID_H(EXTID) ((uint16_t)(((EXTID <<3) | 0x04) >> 16))
#define CAN_FILTER_EXTID_L(EXTID) ((uint16_t)(( EXTID <<3) | 0x04))
#define CAN_STD_ID_H_MASK_CARE (0xFFE0)
#define CAN_STD_ID_L_MASK_CARE (0x0000)
#define CAN_STD_ID_H_MASK_DONT_CARE (0x0000)
#define CAN_STD_ID_L_MASK_DONT_CARE (0x0000)
#define CAN_EXT_ID_H_MASK_CARE (0xFFFF)
#define CAN_EXT_ID_L_MASK_CARE (0xFFF8)
#define CAN_EXT_ID_H_MASK_DONT_CARE (0x0000)
#define CAN_EXT_ID_L_MASK_DONT_CARE (0x0000)
void CAN_Configuration(void)
{
......
CAN_FilterInitType CAN_FilterInitStructure;
CAN_FilterInitStructure.Filter_Num = 0;
CAN_FilterInitStructure.Filter_Mode = CAN_Filter_IdMaskMode;
CAN_FilterInitStructure.Filter_Scale = CAN_Filter_32bitScale;
CAN_FilterInitStructure.Filter_HighId = CAN_FILTER_STDID(0x400);
CAN_FilterInitStructure.Filter_LowId = CAN_FILTER_STDID(0x400);
CAN_FilterInitStructure.FilterMask_HighId = CAN_STD_ID_H_MASK_DONT_CARE;
CAN_FilterInitStructure.FilterMask_LowId = CAN_STD_ID_H_MASK_DONT_CARE;
CAN_FilterInitStructure.Filter_FIFOAssignment = CAN_FIFO0;
CAN_FilterInitStructure.Filter_Act = ENABLE;
CAN1_InitFilter(&CAN_FilterInitStructure);
CAN_INTConfig(CAN1, CAN_INT_FMP0, ENABLE);
......
}
3.4.CAN中断配置及处理
CanRxMessage CAN_RxMessage[10];
uint8_t CAN_RxMessage_WriteCursor = 0;
uint8_t CAN_RxMessage_ReadCursor = 0;
void CAN_Configuration(void)
{
......
NVIC_InitType NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void CAN1_RX0_IRQHandler(void)
{
CAN_ReceiveMessage(CAN1, CAN_FIFO0, &CAN_RxMessage[CAN_RxMessage_WriteCursor++]);
if (CAN_RxMessage_WriteCursor > 10)
{
CAN_RxMessage_WriteCursor = 0;
}
}
3.5.接收发送处理
void CAN_RxMessageHandler(void)
{
uint8_t i = 0;
if (CAN_RxMessage_ReadCursor != CAN_RxMessage_WriteCursor)
{
printf("\r\n");
if (CAN_RxMessage[CAN_RxMessage_ReadCursor].IDE == CAN_Extended_Id)
{
printf("\r\nReceive Frame[0x%X, %d]:", CAN_RxMessage[CAN_RxMessage_ReadCursor].ExtId, CAN_RxMessage[CAN_RxMessage_ReadCursor].DLC);
}
else
{
printf("\r\nReceive Frame[0x%X, %d]:", CAN_RxMessage[CAN_RxMessage_ReadCursor].StdId, CAN_RxMessage[CAN_RxMessage_ReadCursor].DLC);
}
for (i = 0; i < CAN_RxMessage[CAN_RxMessage_ReadCursor].DLC; i++)
{
printf(" 0x%02X", CAN_RxMessage[CAN_RxMessage_ReadCursor].Data[i]);
}
CAN_RxMessage_ReadCursor++;
if (CAN_RxMessage_ReadCursor > 10)
{
CAN_RxMessage_ReadCursor = 0;
}
printf("\r\n");
}
}
void CAN_TxStdMessage(void)
{
CanTxMessage CAN_TxMessage;
uint8_t TxMailbox = 0;
uint8_t i = 0;
CAN_TxMessage.StdId = 0x0400;
CAN_TxMessage.IDE = CAN_ID_STD;
CAN_TxMessage.RTR = CAN_RTRQ_DATA;
CAN_TxMessage.DLC = 8;
for (i = 0; i < CAN_TxMessage.DLC; i++)
{
CAN_TxMessage.Data[i] = i;
}
TxMailbox = CAN_TransmitMessage(CAN1, &CAN_TxMessage);
if (TxMailbox != CAN_TxSTS_NoMailBox)
{
while (CAN_TransmitSTS(CAN1, TxMailbox) != CANTXSTSOK)
{
__ASM("nop");
}
}
else
{
printf("\r\n%s CAN_TxSTS_NoMailBox!!!", __FUNCTION__);
}
}
void CAN_TxExtMessage(void)
{
CanTxMessage CAN_TxMessage;
uint8_t TxMailbox = 0;
uint8_t i = 0;
CAN_TxMessage.ExtId = 0x12345678;
CAN_TxMessage.IDE = CAN_ID_EXT;
CAN_TxMessage.RTR = CAN_RTRQ_DATA;
CAN_TxMessage.DLC = 8;
for (i = 0; i < CAN_TxMessage.DLC; i++)
{
CAN_TxMessage.Data[i] = i;
}
TxMailbox = CAN_TransmitMessage(CAN1, &CAN_TxMessage);
if (TxMailbox != CAN_TxSTS_NoMailBox)
{
while (CAN_TransmitSTS(CAN1, TxMailbox) != CANTXSTSOK)
{
__ASM("nop");
}
}
else
{
printf("\r\n%s CAN_TxSTS_NoMailBox!!!", __FUNCTION__);
}
}
4.测试结果
4.1.PC端使用PCAN工具收发数据
4.2.MCU在接收到CAN数据后,通过串口打印输出
4.3.硬件连接
需要注意的是我们使用的是CAN1,需要将J10这两个跳帽给短接上!!!
5.附件程序
- 2024-02-07
-
发表了主题帖:
【国民技术车规MCU N32A455开发板】01、搭建开发环境、创建基础工程
1.开箱
春节前夕,收到了板载国民技术车规MCU的N32A455开发板!一块开发板、一根MiniUSB数据线……
2.准备工作
2.1.下载开发资料:
通过ftp://download.nationstech.com下载开发板相关资料:ftp://download.nationstech.com/2-Automotive-Grade MCU/下的N32A455xx_V1.2.0.zip
通过https://www.nationstech.com/zlxz455/官网去下载相应资料,
通过测评活动链接,下载官方提供的资料
额……还是建议到FTP服务器去下载,更新比较及时,官网上当前能下载到版本为1.1版本,FTP服务器最新版本为1.2
2.2.安装KEIL集成开发环境芯片支持包
在N32A455xx_V1.2.0\6-Software Development Kit目录下,双击Nationstech.N32A455_DFP.1.0.0.pack进行安装:
3.熟悉板载功能
我们这次测评的开发板型号为N32A455VEL7-EVB,所以对应的是N32A455xx_V1.2.0\5-Hardware Evaulation Board\N32A455VEL7-EVB_V1.1目录下的N32A455VEL7-EVB_V1.1.pdf原理图,通过N32A455VEL7-EVB开发板硬件使用指南,获知开发板功能如下:
开发板供电方式:通过DC插口供12V电源、通过MiniUSB接口供5V电源
板载NSLINK程序下载调试工具,支持JTAG和SWD两种连接方式,同时还带有一路虚拟串口
支持2路CAN和2路LIN
支持TF卡,SDIO接口
板载VS1053B音频电路
板载EEPROM
板载SPI FLASH和QSPI FLASH
板载5个机械按键,1个复位按键、1个唤醒按键、3个功能按键
板载三色LED灯、ADC功能的可调电阻
芯片的所有引脚都通过排针全部引出
4.基础工程
官方的示例程序存放在N32A455xx_V1.2.0\6-Software Development Kit\Nationstech.N32A455_Library.1.1.0目录下,firmware文件夹中存放的是驱动库程序,projects\n32a455_EVAL文件夹下存放的是基于开发板的示例程序。我们参考examples\GPIO\LedBlink示例程序、examples\GPIO\LedBlink示例程序、examples\USART\Printf示例程序,来创建一个新的基础工程。
4.1.创建工程:工程名->选择芯片型号->OK
4.2.添加工程源码:启动程序、CMSIS、驱动库、用户程序
4.3.配置工程
4.4.编写程序
#ifndef __MAIN_H__
#define __MAIN_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdio.h>
#include "n32a455.h"
/* PA11_RLED */
#define RLED_RCC RCC_APB2_PERIPH_GPIOA
#define RLED_GPIO GPIOA
#define RLED_PIN GPIO_PIN_11
/* PB10_BLED */
#define BLED_RCC RCC_APB2_PERIPH_GPIOB
#define BLED_GPIO GPIOB
#define BLED_PIN GPIO_PIN_10
/* PA12_GLED */
#define GLED_RCC RCC_APB2_PERIPH_GPIOA
#define GLED_GPIO GPIOA
#define GLED_PIN GPIO_PIN_12
/* PD12_KEY */
#define S3_RCC RCC_APB2_PERIPH_GPIOD
#define S3_GPIO GPIOD
#define S3_PIN GPIO_PIN_12
/* PC6_KEY */
#define S4_RCC RCC_APB2_PERIPH_GPIOC
#define S4_GPIO GPIOC
#define S4_PIN GPIO_PIN_6
/* PC7_KEY */
#define S5_RCC RCC_APB2_PERIPH_GPIOC
#define S5_GPIO GPIOC
#define S5_PIN GPIO_PIN_7
#ifdef __cplusplus
}
#endif
#endif
#include "main.h"
void LED_Init(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_EnableAPB2PeriphClk(RLED_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = RLED_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(RLED_GPIO, &GPIO_InitStructure);
GPIO_WriteBit(RLED_GPIO, RLED_PIN, Bit_SET);
RCC_EnableAPB2PeriphClk(BLED_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = BLED_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(BLED_GPIO, &GPIO_InitStructure);
GPIO_WriteBit(BLED_GPIO, BLED_PIN, Bit_SET);
RCC_EnableAPB2PeriphClk(GLED_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GLED_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitPeripheral(GLED_GPIO, &GPIO_InitStructure);
GPIO_WriteBit(GLED_GPIO, GLED_PIN, Bit_SET);
}
void LED_ON(GPIO_Module *GPIOn, uint16_t PINn)
{
GPIO_WriteBit(GPIOn, PINn, Bit_RESET);
}
void LED_OFF(GPIO_Module *GPIOn, uint16_t PINn)
{
GPIO_WriteBit(GPIOn, PINn, Bit_SET);
}
void LED_Toggle(GPIO_Module *GPIOn, uint16_t PINn)
{
if (GPIO_ReadOutputDataBit(GPIOn, PINn) == Bit_RESET)
{
GPIO_WriteBit(GPIOn, PINn, Bit_SET);
}
else
{
GPIO_WriteBit(GPIOn, PINn, Bit_RESET);
}
}
void KEY_Init(void)
{
GPIO_InitType GPIO_InitStructure;
RCC_EnableAPB2PeriphClk(S3_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = S3_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitPeripheral(S3_GPIO, &GPIO_InitStructure);
RCC_EnableAPB2PeriphClk(S4_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = S4_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitPeripheral(S4_GPIO, &GPIO_InitStructure);
RCC_EnableAPB2PeriphClk(S5_RCC, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = S5_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitPeripheral(S5_GPIO, &GPIO_InitStructure);
}
void USART_Configuration(void)
{
GPIO_InitType GPIO_InitStructure;
USART_InitType USART_InitStructure;
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_AFIO, ENABLE);
GPIO_InitStruct(&GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1, ENABLE);
USART_StructInit(&USART_InitStructure);
USART_InitStructure.BaudRate = 115200;
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.Mode = USART_MODE_TX;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_Init(USART1, &USART_InitStructure);
USART_Enable(USART1, ENABLE);
}
int main(void)
{
LED_Init();
KEY_Init();
USART_Configuration();
printf("\r\nN32A455VEL7-EVB V1.1 %s %s", __DATE__, __TIME__);
while (1)
{
GPIO_WriteBit(RLED_GPIO, RLED_PIN, GPIO_ReadInputDataBit(S3_GPIO, S3_PIN));
GPIO_WriteBit(BLED_GPIO, BLED_PIN, GPIO_ReadInputDataBit(S4_GPIO, S4_PIN));
GPIO_WriteBit(GLED_GPIO, GLED_PIN, GPIO_ReadInputDataBit(S5_GPIO, S5_PIN));
}
}
int fputc(int ch, FILE* f)
{
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXDE) == RESET);
return (ch);
}
5.编译、运行
5.1.打印输出
5.2.运行视频
[localvideo]ed26d6103ac4f6c11bdcac0a0478b139[/localvideo]
6.附件
- 2024-02-05
-
回复了主题帖:
【小华工控新品HC32F448】06.WDT/SWDT看门狗计数器给程序的正常运行保驾护航
Jacktang 发表于 2024-2-5 07:48
看门狗计数器用的很好啊,学习学习
-
回复了主题帖:
【小华工控新品HC32F448】07.使用XHCode基于HC32F448创建闪烁LED基础工程
Jacktang 发表于 2024-2-5 07:46
可以把这个贴当做用XHCode创建一个闪烁LED的基础工程的教程啦
- 2024-02-04
-
发表了主题帖:
【小华工控新品HC32F448】07.使用XHCode基于HC32F448创建闪烁LED基础工程
本帖最后由 xld0932 于 2024-2-4 14:27 编辑
1.概述
XHCode是小华半导体推出的一款协助用户配置生成XHSC MCU基础代码的软件工具,它包含了管脚和模块配置、时钟配置和工程配置3部分,今天来基于HC32F448系列MCU,使用XHCode创建一个闪烁LED的基础工程,来记录一下使用体验。
2.安装XHCode
从小华半导体官网上可以下载最新版本的XHCode工具,双击安装文件,根据提示进行安装,这个安装过程比较简单,如下所示:
3.创建闪烁LED工程
3.1.双击XHSC XHCode软件,在左上角型号的下拉菜单中选择HC32F448MCTI-LQFP80,如下所示:
3.2.管脚和模块配置界面:在左侧MCU引脚配置图中先配置一些基础配置,比如PA13\PA14配置为程序调试/烧录引脚、配置PC14/PC15为外部32.768晶振的输入端口、配置PH0/PH1为外部主晶振的输入端口;然后根据EV_F448_LQ80_Rev1.0开发板的原理图,将PA2配置为GPIO-Output输出模式,如下所示:
在配置GPIO时,发现现在还有少部分的外设无法配置,可能需要后面更新版本后才能配置吧;但对于GPIO来说,没有重命名Lable的功能,觉得有些不方便,将PA2添加一个LED的Lable,会显示更直观,更清楚不是么……
3.3.时钟配置界面:当选择HC32F448MCTI-LQFP80这颗芯片型号后,系统的时钟和总线频率配置大部分都是依据最大上限来配置的,个别没有达到上限的也是因为计算分频倍数的关系,同时满足不了多端的要求,就优先满足一边了,如下图所示:
在看这个时钟配置时,默认PLLSRC就是选用的XTAL,当在配置管脚和模块配置界面还没有配置时钟引脚时,这边就是这样的默认选择了,感觉管脚和模块配置界面与时钟配置界面的功能并没有联动起来,感觉有点功能欠缺的意思;另外就是在时钟配置界面上,对于频率的显示单位也没有统一起来,一部分单位是MHz,一部分的单位却是KHz,看上去有些杂乱。
3.4.工程配置界面:我们在工程名称中输入相应的工程名,选择工程IDE类型为MDK(这个工具支持KEIL MKD、IAR EWARM、Eclipse三个集成开发环境的工程生成),指定工程保存的位置以及驱动库(DDL)位置,先点击右上角的保存配置保存当前的工程,然后再点击右上角的生成代码,依据我们的工程配置生成相应的代码,如下所示:
需要注意的是,驱动库(DLL)位置不是指DLL下载存放的位置,当前这款工具还没有根据芯片型号自动下载对应驱动库程序的功能,而是需要我们提前下载好DLL驱动库,然后这边指定位置就是我们存放下载的DLL驱动库的位置:
3.5.生成的代码:我们发现生成的代码目录如下所示,有main和MDK两个文件夹,后面我才确认这边的main文件夹是多余的,因为MDK工程中的源程序,都是存放在MDK目录中的,所以这边需要原厂制作工具的再确认下:
4.编译工程
4.1.打开MDK目录下的LED.uvprojx工程文件,如下所示:
4.2.我们先想看一工程的配置,点击工具栏的配置按钮,在弹出配置窗口的Debug选项卡中确认使用的调试下载工具,然后再通过Utilities选项卡确认下载选项,如下所示:
我们需要将Reset and Run勾选上,这样我们在程序下载完成后,芯片就可以自动复位并运行了。
4.3.我们点击工具栏的工程编译按钮,编译结果发现有2处Error,对于官方示例程序,发现没有配置这2条语句的选项,所以就先屏蔽掉了,结果编译就顺利通过了:
自动生成的代码会产生编译错误实属不应该哈,大多数使用自动生成工具的来说,就是想快速的生产工程,对底层配置不想深究太多,出错后就不得不多花时间去检查了……
5.应用程序
在编译无误的工程上,我们就可以添加自己的应用程序了,因为闪烁LED的功能比较简单,我们就直接在main函数的for循环里添加了,每间隔500ms,LED显示状态翻转一次:
/**
* @brief Main function of the project
* @param None
* @retval int32_t return value, if needed
*/
int32_t main(void)
{
/* Register write unprotected for some required peripherals. */
LL_PERIPH_WE(LL_PERIPH_ALL);
//Clock Config
App_ClkCfg();
//Port Config
App_PortCfg();
/* Register write protected for some required peripherals. */
LL_PERIPH_WP(LL_PERIPH_ALL);
for (;;) {
GPIO_TogglePins(GPIO_PORT_A, GPIO_PIN_02);
DDL_DelayMS(500);
}
}
最后编译无误,下载运行OK哦!
6.总结
XHCode是一款用来便于开发的软件,理应做到配置功能齐全、生成代码无误,要做到这一点,XHCode还有很多工作需要去做,去测试、去完善、去适配;希望这款工具越做越好,尽早的可以给开发工程师带来便利!
-
回复了主题帖:
测评入围名单: 国民技术车规MCU N32A455开发板
个人信息无误,确认可以完成评测计划。
-
回复了主题帖:
【小华工控新品HC32F448】01.搭建开发环境、创建基础工程
Maker_kun 发表于 2024-1-22 19:41
开发板外设挺丰富的
嗯,除了板载资源,芯片所有的引脚也都扩展出来了,方便接一些其它的外设做测试验证