请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
器件型号:TMS320F28069M /**
* SPI DMA 传输到 SSD1306 OLED 显示屏
*
*该示例使用数字回路(DLB)在内部传输8位数据
*使用 SPI 主控模式下的 McBSP 模块,支持8位 DMA。
*
*可以在以下 McBSP 引脚上观察到这些波形:
*
SSD1306 McBSP GPIO 引脚 信号
*--------------------------------
*重置 -> GPIO23 ->引脚#49
* D/C -> GPIO44 ->引脚#18
* SCLK -> MCLKX -> GPIO22 ->引脚#08 -> SPICLK
* MOSI -> MDX -> GPIO20 ->引脚#45 -> SPISIMO
*
*对于 McBSP 示例、McBSP 采样率发生器(SRG)
*输入时钟频率默认为4 MCLK /SPISIMO *。
//
#include "DSP28x_Project.h"
#define LCDWIDTH 128 /* cols 0-127 */
#define LCDHEIGHT 64 /*行0 - 63 */
#define LAST_PAGE 7. /*页尾地址 */
#define LCD_Pixels (LCDWIDTH * LCDHEIGHT)
#define LCD_Bytes (lcd_pixels / 8)
#define LAST_COL (LCDWIDTH)
#define LAST_ROW (LCDHEIGHT)
#pragma DATA_SECTION (RDATA、"DMARAML5") DMA L5 SRAM 中的/*缓冲区 */
uint16 RDATA[1024]; /*接收的数据 */
#pragma DATA_SECTION (sdata、"DMARAML5") DMA L5 SRAM 中的/*缓冲区 */
uint16 sdata[128]; /*发送数据 */
#define SETLOWCOLUMN 0x00
#define EXTERNALVCC 0x01
#define SWITCHCCAPVCC 0x02
#define SETHIGHCOLUMN 0x10
#define memorymode 0x20
#define COLUMNADDR 0x21
#define PAGEADDR 0x22
#define SCROL_ENABLE 0x2F
#define SCROL_DISABLE 0x2E
#define SCROL_SET_VERT_AREA 0xA3
#define SCROL_RIVE_HORIZ 0x26
#define SCROL_LEFT_HORIZAL 0x27
#define SCROL_VERT_RIGHT _HORIZ 0x29
#define SCROL_VERT_LEFT_HORIZ 0x2A
#define SETSTARTLINE 0x40
#define SETCONTRAST 0x81
#define CHARGEPUMP 0x8D
#define SEGREMAP 0xA0
#define SETSEGMENTREMAP 0xA1
#define DISPLAYALLON_RESUME 0xA4
#define DISPLAYALLON 0xA5
#define NORMALDISPLAY 0xA6
#define INVERTDISPLAY 0xA7
#define SETMULTIPLEX 0xA8
#define DISPLAYOFF 0xAE
#define DISPLAYON 0xAF
#define COMSCANINC 0xC0
#define COMSCANDEC 0xC8
#define SETDISPLAYOFFSET 0xD3
#define SETDISPLAYCLOCKDIV 0xD5
#define SETPRECHARGE 0xD9
#define SETCOMPINS 0xDA
#define SETVCOMDETECT 0xDB
#pragma DATA_SECTION (INIT、"DMARAML5"); /* DMA L5 SRAM 中的 dmatab */
uint16 init[]={
0xae、 /* DISPLAYOFF *
0xD5、 /*将 SETDISPLAYCLOCKDIV 更改为0x80 *
0x80、
0xa8、 /* SEMULTIPLEX *
LCDHEIGHT - 1、
0xD3、 /*将 SETDISPLAYOFFSET 设置为0x00 *
0x00、
0x40、 /*第0行| SETSTARTLINE *
0x8d、 /* CHARGEPUMP 设置 *
0x14、
0x20、 /*内存模式寻址 *
0x00、
0xA0 | 0x1、 /* SEGREMAP *
0xc8、 /* COMSCANDEC *
0xDA、 /* SETCOMPINS *
0x12、
0x81、 /* SETCONTRAST 至0xef *
0xCF、
0xd9、 /* SETPRECHARGE 周期 *
0xF1、
0xdb、 /* SETVCOMDETECT 电平 *
0x40、
0xa4、 /* DISPLAYALLON_RESUME *
0xa6、 /* NORMALDISPLAY *
0x2E、 /* SCROL_DISABLE *
0xaf、 /* DISPLAYON */
};
#define black 0
#define white 1
#define 反向 2
typedef int int16_t;
typedef int int8_t;
typedef uint8 uint8_t;
typedef unsigned int uint16_t;
typedef unsigned char uchar;
volatile enum dmaio_state{
IO_COMPLETE = 0、
IO_PENDING = 1、
}io_state;
#define ssd1306_swap (a、b) {int16_t t = a;a = b;b = t;}
#pragma DATA_SECTION (fb、"DMARAML5") DMA L5 SRAM 中的/*缓冲区 /uint16
fb[1024];
/**
* McBSP_init_delay 确定
McBSP 初始化例程所需的2个采样率*发生器(SRG)周期内的 CPU 周期数。
* McBSP_CLKG_DELAY 确定
McBSP 初始化例程所需的2个时钟*发生器(CLKG)周期中的 CPU 周期数。
*/
#define CPU_SPD 80E6
#define McBSP_SRG_FREQ CPU_SPD/2 /* SRG 输入= LSPCLK (SYSCLKOUT/2)*/
#define McBSP_DELAY 2*(CPU_SPD/McBSP_SRG_FREQ)// CPU 周期在2个 SRG 初始化延迟中*/
void delay_loop (void)
{
长 I;
对于(i = 0;i < McBSP_delay;i++){} /*必须至少为2个 SRG 周期*/
}
void error (void)
{
_asm (" ESTOP0"); /*出错时停止 *
对于(;;);
}
void init_mcbspa_pio (void)
{
EALLOW;
GpioCtrlRegs.GPAMUX2.bit.GPIO20 = 2; /* GPIO20=MDXA、数据 TX、MOSI *
GpioCtrlRegs.GPAMUX2.bit.GPIO22 = 2; /* GPIO22=CLKXA、CLK TX、SCL *
GpioCtrlRegs.GPAQSEL2.bit.GPIO22 = 3; /*异步输入 GPIO22 (MCLKXA) *
EDIS;
}
void dma_xfer (uint16 * src、uint16 len)
{
io_state = io_PENDING; /*不允许同时传输*/
EALLOW;
DMACTRL.bit.hardreset = 1;
_asm (" NOP"); /*每个设计只需要1 NOP *
/**
*通道1、McBSPA 发送
*
DMaRegs.CH1.MODE.BIT.CHINTE = 0;
DmaRegs.ch1.burse_size.all = 0; /* 1字/突发 *
DMARegs.CH1.SRC_BURST_STEP = 0; /* 1字/突发无影响 *
DmaRegs.CH1.dst_burst_step = 0; /* 1字/突发无影响 *
DMARegs.CH1.TRANSF_SIZE = len; /* len 后的中断 *
DMARegs.CH1.SRC_TRANSFER_STEP = 1; /*在每个字上增加地址*/
DmaRegs.CH1.dst_transfer_step = 0; /*不要改变分度 *
DmaRegs.CH1.SRC_ADDR_SHADDow =(uint32) src; /*源是缓冲区 *
DmaRegs.CH1.SRC_beg_ADDR_SHADDow =(uint32) src; /*仅适用于包装 *
DmaRegs.CH1.dst_ADDR_SHADDow =(uint32)&McbspaRegs.DXR1.all;/* Dest。 McBSPA DXR */
DmaRegs.CH1.dst_beg_ADDR_SHADDADDR =(uint32)&McbspaRegs.DXR1.all;/*仅用于包装 fn *
DmaRegs.ch1.control.bit.PERINTCLR = 1; /*清除中断事件标志 *
DmaRegs.CH1.control.bit.ERRCLR = 1; /*清除同步错误标志 *
DmaRegs.CH1.dst_wrap_size = 0xFFFF; /*最大长度,无目标环绕 *
DMARegs.CH1.SRC_WOP_SIZE = 0xFFFF; /*最大长度,无源绕线 *
DMaRegs.CH1.MODE.BIT.CHINTE = 1; /*启用通道中断 *
DMaRegs.CH1.MODE.BIT.CHINTMODE = 1; 传输结束时的/*中断 *
DMaRegs.CH1.MODE.BIT.PERINTE = 1; /*启用外设中断 *
DMARegs.CH1.MODE.BIT.PERINTSEL = DMA_MXEVTA; /* McBSPA 外设、MXSYNCA int */
DmaRegs.ch1.control.bit.PERINTCLR = 1; /*清除伪中断标志*/
/**
*通道2、McBSPA 接收
*如果我们没有读取下一个 SPI 帧失败、我们确实需要读取
*通过将突发读取到同一个缓冲区中来保存接收缓冲区大小
*
DMaRegs.CH2.MODE.BIT.CHINTE = 0;
DmaRegs.ch2.burse_size.all = 0; /* 1字/突发 *
DMARegs.CH2.SRC_BURST_STEP = 0; /* 1字/突发无影响 *
DmaRegs.CH2.dst_burst_step = 0; /* 1字/突发无影响 *
DmaRegs.ch2.transfer_size = len; /* len 后的中断 *
DMARegs.CH2.SRC_TRANSFER_STEP = 0; /*不要移动源地址 *
DmaRegs.CH2.dst_transfer_step = 1; /*不要移动分页地址*/
DmaRegs.CH2.SRC_ADDR_SHADDR =(uint32)&McbspaRegs.DR1.all;//源为 McBSPA DRR */
DmaRegs.CH2.SRC_beg_ADDR_SHADDR =(uint32)&McbspaRegs.DRR1.all;//*仅用于包装 fn *
DmaRegs.CH2.dst_ADDR_SHADDow =(uint32)&RDATA[0]; /*目标 缓冲器 *
DmaRegs.ch2.dst_beg_ADDR_shadow =(uint32)&RDATA[0]; /*仅适用于包装 *
DmaRegs.ch2.control.bit.PERINTCLR = 1; /*清除中断事件标志 *
DMaRegs.CH2.CONTROL.BIT.ERRCLR = 1; /*清除同步错误标志 *
DmaRegs.CH2.dst_wrap_size = 0xFFFF; /*最大长度,无目标环绕 *
DMARegs.CH2.SRC_WOP_SIZE = 0xFFFF; /*最大长度,无源绕线 *
DMaRegs.CH2.MODE.BIT.CHINTE = 1; /*启用通道中断 *
DMaRegs.CH2.MODE.BIT.CHINTMODE = 1; 传输结束时的/*中断 *
DMaRegs.CH2.MODE.BIT.PERINTE = 1; /*启用外设中断 *
DMARegs.CH2.MODE.BIT.PERINTSEL = DMA_MREVTA; /* McBSPA 外设、MRSYNCA int */
DmaRegs.ch2.control.bit.PERINTCLR = 1; /*清除伪中断标志*/
/*启动 DMA */
DmaRegs.ch1.control.bit.run = 1; /*开始 McBSPA DMA 传输*/
DmaRegs.ch2.control.bit.run = 1; /*开始 McBSPA DMA 接收 *
EDIS;
/* init SPI 外设*/
McbspaRegs.SPCR2.all = 0x0000; /*重置 FS 生成、SRG 和 Tx *
McbspaRegs.SPCR1.all = 0x0000; /*重置 Rx、右对齐、DLB dis */
McbspaRegs.pcr.all = 0x0F08; /*(CLKXM=CLKRM=FSXM=FSRM=1、FSXP=1)*/
McbspaRegs.SPCR1.bit.DLB = 1;
McbspaRegs.MFFINT.ALL = 0x0; /*禁用所有中断 *
McbspaRegs.SPCR1.bit.CLKSTP= 3; 具有 CLKXP/CLKRP 的/*时钟架构*/
McbspaRegs.pcr.bit.CLKXP=0; /* CPOL=0、CPHA=1、上升沿、无延迟*/
McbspaRegs.pcr.bit.CLKRP = 0; /*如果 CLKSTP=2,则 CPHA=0 *
McbspaRegs.RCR2.bit.RDATDLY = 01; /* FSX 设置时间1 =主控模式*/
McbspaRegs.XCR2.bit.XDATDLY=01; /* FSX 设置时间1 =主控模式*/
McbspaRegs.RCR1.bit.RWDLEN1 = 0; /* 5=32位字 *
McbspaRegs.XCR1.bit.XWDLEN1 = 0; /* 5=32位字 *
McbspaRegs.SRGR2.all = 0x2000; /* CLKSM=1、FPER=1 CLKG 周期 *
McbspaRegs.SRGR1.all = 0x000f; /*帧宽度=1、CLKGDV=16;0x0F *
McbspaRegs.SPCR2.bit.GRST = 1; /*启用采样率发生器*/
delay_loop(); /*等待至少2个 SRG 时钟周期*/
McbspaRegs.SPCR2.bit.XRST = 1; /*从复位释放 TX *
McbspaRegs.SPCR1.bit.RRST = 1; /*从复位中释放 RX *
McbspaRegs.SPCR2.bit.frst = 1; /*帧同步发生器复位 */
}
void ssd1306_reset (void)
{
GpioDataRegs.GPACLEAR.bit.GPIO23 = 1; /*复位= 0 *
DELAY_US (10000); /*等待10ms *
GpioDataRegs.GPASET.bit.GPIO23 = 1; /*复位= 1. *
DELAY_US (50000); /*等待50mS */
}
void ssd1306_init (void)
{
GpioDataRegs.GPBCLEAR.bit.GPIO44 = 1; /* D/C 默认低电平(CMD 模式) *
dma_xfer (init、sizeof (init)); /* SSD1306初始化 */
}
void setup_LCD_PINS (void)
{
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO23 = 1; /*禁用复位的上拉电阻 *
GpioCtrlRegs.GPBPUD.bit.GPIO44 = 1; 针对 D/C 的/*禁用上拉电阻器 *
GpioCtrlRegs.GPAMUX2.bit.GPIO23 = 0; /*设置 GPIO::复位 *
GpioCtrlRegs.GPBMUX1.bit.GPIO44 = 0; /*设置 GPIO:D/C *
GpioCtrlRegs.GPADIR.bit.GPIO23 = 1; /*设置输出::重置 *
GpioCtrlRegs.GPBDIR.bit.GPIO44 = 1; /*设置输出:D/C *
EDIS;
GpioDataRegs.GPASET.bit.GPIO22 = 1; /*重置默认高电平(释放) */
}
void lcd_fb_put (void)
{
while (IO_state!= IO_COMPLETE); /*等待 DMA 完成 *
GpioDataRegs.GPBSET.BIO44 = 1; /* D/C 默认高电平(数据模式) *
dma_xfer (fb、sizeof (fb)); /* SSD1306图形数据 */
}
void fb_clear (void)
{
uint8 i;
while (IO_state!= IO_COMPLETE); /*等待 DMA 完成 *
对于(I = 0;I <(LCDWIDTH * LCDHEIGHT / 8);I++)
FB[i]= 0x00;
}
//**
*设置用于 CGRAM 访问的窗口区域
* void LCD_set_window (uint16_t c_start、
* uint16_t p_start、
* uint16_t c_stop、
* uint16_t p_stop)
*
*@uint16_t c_start:列起始地址
*@uint16_t p_start:页起始地址
*@uint16_t c_stop :列结束地址
*@uint16_t p_stop :页面结束地址
*/
void lcd_set_window (uint16_t c_start、
uint16_t p_start、
uint16_t c_stop、
uint16_t p_stop)
{
sdata[0]= COLUMNADDR; /*设置列地址(0x21) *
sdata[1]= c_start; /* COL start;例如0 *
sdata[2]= c_stop; /*列结束;最大'lcdwidth -1';127 */
sdata[3]= PAGEADDR; /*设置页地址(0x22) *
sdata[4]= p_start; /*页开始;0 *
sdata[5]= p_stop; /*页尾;max=7 ((lcdheight /8)-1)*/
while (IO_state!= IO_COMPLETE); /*等待 DMA 完成 *
GpioDataRegs.GPBCLEAR.bit.GPIO44 = 1; /* CMD 模式 *
dma_xfer (sdata、5); /*传输6字节 */
}
/* INT7.1是 DMA Ch1 */
_中断 void ISR_DMA_CH1 (void)
{
EALLOW;
DmaRegs.ch1.control.bit.halt = 1;
PieCtrlRegs.PIEACX.ALL = PIEACK_group7; /*中断 ACK *
EDIS;
return;
}
/* INT7.2为 DMA Ch2 */
_中断 void ISR_DMA_CH2 (void)
{
EALLOW;
DmaRegs.ch2.control.bit.halt = 1;
PieCtrlRegs.PIEACX.ALL = PIEACK_group7; /*中断 ACK *
io_state = io_complete;
EDIS;
return;
}
void main (void)
{
InitSysCtrl();
init_mcbspa_pio();
Dint;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EALLOW;
PieVectTable.DINTCH1 =&ISR_DMA_CH1; /* Tx ISR DMA 通道1 INT7.1 *
PieVectTable.DINTCH2 =&ISR_DMA_CH2; /* Rx ISR DMA CH2 INT7.2 *
EDIS;
Setup_LCD_PINS ();
ssd1306_reset (); /*重置 LCD *
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; /*启用 PIE 块 *
PieCtrlRegs.PIEIER7.bit.INTx1 = 1; /*启用 PIE 组7 INT1 (DMA CH1)*/
PieCtrlRegs.PIEIER7.bit.INTx2 = 1; /*启用 PIE 组7 INT2 (DMA CH2)*/
IER = 0x40; /*启用 CPU INT 组7 *
EINT; /*启用全局中断 *
ssd1306_init(); /*初始化 LCD *
FB_clear(); /*清除 fb 数组 *
LCD_SET_WINDOW (0、0、127、7); /* col:0-127、page:0-7访问 *
FB[0]= 0xff; /*绘制8个像素@x=0,y=0-7 *
lcd_fb_put (); /*写入 ssd1306 *
while (1){}