【MM32F5270开发板试用】快速移植STM32应用到MM32F5270(以OLED为例)
本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:@#@
本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:@#@
最近在做几个嵌入式项目,一直使用的是STM32F429作为主控制芯片。从去年开始,ST的芯片全系涨价,价格高到离谱,并且市场上充斥着翻新芯片,有时候有钱都不一定能买到靠谱的原装芯片。考虑到项目最终落地需要考虑到芯片供应问题,所以一直在寻找国产替代。正好看到极术社区的MM32F5270适用活动,初步看芯片性能以及外设接口能满足现在的项目需求,所以申请一个板子来看下从STM32移植到MM32F5270的工作量。
一 项目简介
最近做的项目是一个气体分析仪,基本原理框图如下。
用STM32跑PID算法,控制比例阀开度,将输入气流稳定到设置值,然后由气体检测器进行采样并处理。这个项目目前已经开始小批量出货,这里就不过多说明技术细节。
由于项目客制化需求比较多,要求能够通过键盘选择不同功能,涉及到多级菜单。所以大量的工作都在自定义的菜单设计和实现上,这里就先试试移植OLED驱动代码到MM32F5270看看工作量。
二 环境准备
请参考https://aijishu.com/a/1060000…准备开发环境。记住,一定要下载MDK5.37版本才能使用灵动微电子的MM32 pack包。
因为我习惯用JLINK调试器做开发,所以这里我就直接使用JLINK作为调试工具。JLINK的插头直接插上去就可以,有防呆设计,不用担心会插错,下面是JLINK连接特写。
插上JLINK后,在魔术棒页面DEBUG tab里选择JLINK/J-TRACE Cortex
点击setting,在setting页面选择SW
接下来就可以愉快的使用JLINK进行MM32F5270开发板的调试了。
三 代码移植
初步看了下Mind SDK的文件结构,对所有的外设,都有对应的驱动代码,驱动代码对底层的硬件操作做了很好的封装。看了下对应的driver_example以及demo_apps,提供的都是类似于如下的代码文件组织结构
对于简单的应用来说,这种结构可以满足需求。但是对于一些外设较多的项目,这种组织形式在逻辑上不是很清晰,且代码复用性不高。所以这里按照项目的需求,设计了按hardware和module分类的方法,项目部分文件结构如下:
其中hardware目录是用到的外设driver,module目录里会放跟硬件无关的功能模块,比如流量控制功能,气体采样功能(当然目前为空,但是因为这是硬件无关逻辑,所以基本上可以不做改动直接移到MM32F5270)等。这里以tim_basic例程为基础,来移植OLED驱动。
- 拆分clock_init.c/clock_init.h文件,这里将所有外设的clokc外设移除,只留下主时钟的初始化。
void BOARD_InitBootClocks(void)
{
CLOCK_ResetToDefault();
CLOCK_BootToHSE120MHz();
}
2.将uart拆分到单独文件,以后在不同项目可以进行复用
demo_uart.h
#ifndef _UART_H_
#define _UART_H_
#include “clock_init.h”
/* DEBUG UART. */
#define BOARD_DEBUG_UART_PORT UART1
#define BOARD_DEBUG_UART_BAUDRATE 9600u
#define BOARD_DEBUG_UART_FREQ CLOCK_APB2_FREQ
void uart1_init(void);
#endif
demo_uart.c
#include “demo_uart.h”
#include
#include “hal_common.h”
#include “hal_gpio.h”
#include “hal_uart.h”
#include “hal_rcc.h”
static void uart1_gpio_init(void)
{
/* PB6 - UART1_TX. */
GPIO_Init_Type gpio_init;
gpio_init.Pins = GPIO_PIN_6;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_7);
/* PB7 - UART1_RX. */
gpio_init.Pins = GPIO_PIN_7;
gpio_init.PinMode = GPIO_PinMode_In_Floating;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
GPIO_PinAFConf(GPIOB, gpio_init.Pins, GPIO_AF_7);
}
static void uart1_port_init(void)
{
UART_Init_Type uart_init;
uart_init.ClockFreqHz = BOARD_DEBUG_UART_FREQ;
uart_init.BaudRate = BOARD_DEBUG_UART_BAUDRATE;
uart_init.WordLength = UART_WordLength_8b;
uart_init.StopBits = UART_StopBits_1;
uart_init.Parity = UART_Parity_None;
uart_init.XferMode = UART_XferMode_RxTx;
uart_init.HwFlowControl = UART_HwFlowControl_None;
UART_Init(BOARD_DEBUG_UART_PORT, &uart_init);
UART_Enable(BOARD_DEBUG_UART_PORT, true);
}
void uart1_init(void)
{
/* UART1. */
RCC_EnableAPB2Periphs(RCC_APB2_PERIPH_UART1, true);
RCC_ResetAPB2Periphs(RCC_APB2_PERIPH_UART1);
/* GPIOB. */
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOB, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOB);
uart1_gpio_init();
uart1_port_init();
}
#if defined(__ARMCC_VERSION)
int fputc(int c, FILE *f)
{
(void)(f);
while ( 0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
UART_PutData(BOARD_DEBUG_UART_PORT, (uint8_t)©);
return c;
}
int fgetc(FILE *f)
{
(void)(f);
while ( 0u == (UART_STATUS_RX_DONE & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
return UART_GetData(BOARD_DEBUG_UART_PORT);
}
#elif defined(__GNUC__)
/*
* Called by libc stdio fwrite functions
*/
int _write(int fd, char *ptr, int len)
{
int i = 0;
/*
* write “len” of char from “ptr” to file id “fd”
* Return number of char written.
*
* Only work for STDOUT, STDIN, and STDERR
*/
if (fd > 2)
{
return -1;
}
while (*ptr && (i < len))
{
while ( 0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
UART_PutData(BOARD_DEBUG_UART_PORT, (uint8_t)(*ptr));
i++;
ptr++;
}
return i;
}
/*
* Called by the libc stdio fread fucntions
*
* Implements a buffered read with line editing.
*/
int _read(int fd, char *ptr, int len)
{
int my_len;
if (fd > 2)
{
return -1;
}
my_len = 0;
while (len > 0)
{
while ( 0u == (UART_STATUS_RX_DONE & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
*ptr = UART_GetData(BOARD_DEBUG_UART_PORT);
len–;
my_len++;
if ( (*ptr == ‘\r’) || (*ptr == ‘\n’) || (*ptr == ‘\0’) )
{
break;
}
ptr++;
}
return my_len; /* return the length we got */
}
int putchar(int c)
{
while ( 0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
UART_PutData(BOARD_DEBUG_UART_PORT, (uint8_t)©);
return c;
}
int getchar(void)
{
while ( 0u == (UART_STATUS_RX_DONE & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
return UART_GetData(BOARD_DEBUG_UART_PORT);
}
#elif (defined(__ICCARM__))
/* These function __write and __read is used to support IAR toolchain to printf and scanf. */
int fputc(int ch, FILE *f)
{
while ( 0u == (UART_STATUS_TX_EMPTY & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
UART_PutData(BOARD_DEBUG_UART_PORT, (uint8_t)(ch));
return ch;
}
int fgetc(FILE *f)
{
while ( 0u == (UART_STATUS_RX_DONE & UART_GetStatus(BOARD_DEBUG_UART_PORT)) )
{}
return UART_GetData(BOARD_DEBUG_UART_PORT);
}
#endif
-
OLED会用到SPI,这里用SPI3作为控制接口
demo_spi.h#ifndef _DEMO_SPI_H_
#define _DEMO_SPI_H_
#include “hal_common.h”
#include “clock_init.h”#define BOARD_LOOP_SPI_PORT SPI3
//#define BOARD_LOOP_SPI_BAUDRATE 1000000u /* 400khz. /
#define BOARD_LOOP_SPI_BAUDRATE 400000u / 400khz. */#define BOARD_LOOP_SPI_FREQ CLOCK_APB1_FREQ
void spi3_init(void);
/* SPI tx. */
void spi3_putbyte(uint8_t c);/* SPI rx. */
uint8_t spi3_getbyte(void);
#endif -
demo_spi.c
#include “demo_spi.h”
#include “hal_rcc.h”
#include “hal_spi.h”
#include “hal_gpio.h”static void spi3_gpio_init(void)
{
GPIO_Init_Type gpio_init;/* SPI3_NSS - PA15. /
/
gpio_init.Pins = GPIO_PIN_15;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_init);
GPIO_PinAFConf(GPIOA, GPIO_PIN_15, GPIO_AF_6);
*//* SPI3_MOSI - PC12. */
gpio_init.Pins = GPIO_PIN_12;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, GPIO_PIN_12, GPIO_AF_6);/* SPI3_MISO - PC11. */
gpio_init.Pins = GPIO_PIN_11;
gpio_init.PinMode = GPIO_PinMode_In_Floating;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, GPIO_PIN_11, GPIO_AF_6);/* SPI3_SCK - PC10. */
gpio_init.Pins = GPIO_PIN_10;
gpio_init.PinMode = GPIO_PinMode_AF_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &gpio_init);
GPIO_PinAFConf(GPIOC, GPIO_PIN_10, GPIO_AF_6);}
static void spi3_port_init(void)
{
/* Setup SPI module. */
SPI_Master_Init_Type spi_init;
spi_init.ClockFreqHz = BOARD_LOOP_SPI_FREQ;
spi_init.BaudRate = BOARD_LOOP_SPI_BAUDRATE;
spi_init.XferMode = SPI_XferMode_TxRx;
spi_init.PolarityPhase = SPI_PolarityPhase_Alt0;
spi_init.DataWidth = SPI_DataWidth_8b;
spi_init.LSB = false;
spi_init.CSMode = SPI_CSMode_NonAuto;
SPI_InitMaster(BOARD_LOOP_SPI_PORT, &spi_init);/* Enable SPI. */
SPI_Enable(BOARD_LOOP_SPI_PORT, true);}
void spi3_init(void)
{
/* GPIOA. /
/
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOA, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOA);
*//* GPIOC. */
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOC, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOC);/* SPI3. */
RCC_EnableAPB1Periphs(RCC_APB1_PERIPH_SPI3, true);
RCC_ResetAPB1Periphs(RCC_APB1_PERIPH_SPI3);spi3_gpio_init();
spi3_port_init();
}/* SPI tx. */
void spi3_putbyte(uint8_t c)
{
/* Polling for tx empty. */
while ( SPI_STATUS_TX_FULL & SPI_GetStatus(BOARD_LOOP_SPI_PORT) )
{}
SPI_PutData(BOARD_LOOP_SPI_PORT, c);
}/* SPI rx. */
uint8_t spi3_getbyte(void)
{
/* Polling for rx done. */
while (0u == (SPI_STATUS_RX_DONE & SPI_GetStatus(BOARD_LOOP_SPI_PORT)) )
{}
return SPI_GetData(BOARD_LOOP_SPI_PORT);
} -
顺便将LED4, LED5的控制单独拉出,可以作为debug的辅助手段
led.h
#ifndef _LED_H_
#define _LED_H_#include “type_def.h”
enum LED_NUM {
LED4,
LED5,
};void led_init(void);
void led_on(u8 led);
void led_off(u8 led);
#endif -
led.c
#include “led.h”
#include “hal_rcc.h”
#include “hal_gpio.h”static void led_gpio_init(void)
{
GPIO_Init_Type gpio_init;/* LED4. */
gpio_init.Pins = GPIO_PIN_0;
gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOI, &gpio_init);/* LED5. */
gpio_init.Pins = GPIO_PIN_2;
gpio_init.PinMode = GPIO_PinMode_Out_PushPull;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &gpio_init);}
void led_init(void)
{
/* GPIOD. */
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOD, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOD);/* GPIOI. */
RCC_EnableAHB1Periphs(RCC_AHB1_PERIPH_GPIOI, true);
RCC_ResetAHB1Periphs(RCC_AHB1_PERIPH_GPIOI);led_gpio_init();
}
void led_on(u8 led)
{
switch (led) {
case LED4:
GPIO_WriteBit(GPIOI, GPIO_PIN_0, 0u);
break;
case LED5:
GPIO_WriteBit(GPIOD, GPIO_PIN_2, 0u);
break;
default:
break;
}
}void led_off(u8 led)
{
switch (led) {
case LED4:
GPIO_WriteBit(GPIOI, GPIO_PIN_0, 1u);
break;
case LED5:
GPIO_WriteBit(GPIOD, GPIO_PIN_2, 1u);
break;
default:
break;
}
} -
以上完成后,OLED驱动移植的前期准备工作已经完成,现在开始将STM32上的OLED控制代码移到MM32F5270上来。OLED使用的是中景园的3.12寸 256X64 单色OLED屏幕,淘宝连接https://item.taobao.com/item…。
控制引脚如图所示
原始STM32控制代码如下所示:
stm32的oled.h
#ifndef __OLED_H#define __OLED_H #include "sys.h"#define OLED_USE_SOFT_SPI 0#define OLED_CS_Pin GPIO_PIN_12#define OLED_CS_GPIO_Port GPIOH#define OLED_DC_Pin GPIO_PIN_12#define OLED_DC_GPIO_Port GPIOB#define OLED_RES_Pin GPIO_PIN_11#define OLED_RES_GPIO_Port GPIOH#if OLED_USE_SOFT_SPI#define SOFT_SPI_MOSI_Pin GPIO_PIN_7#define SOFT_SPI_MOSI_GPIO_Port GPIOF#define SOFT_SPI_MISO_Pin GPIO_PIN_8#define SOFT_SPI_MISO_GPIO_Port GPIOF#define SOFT_SPI_SCK_Pin GPIO_PIN_9#define SOFT_SPI_SCK_GPIO_Port GPIOF#endif#define USE_HORIZONTAL 1 //设置显示方向 0:正向显示;1:旋转180度显示#ifndef PIN_RESET#define PIN_RESET 0#define PIN_SET 1#endifvoid OLED_WR_REG(u8 reg);void OLED_WR_Byte(u8 dat);void Column_Address(u8 a,u8 b);void Row_Address(u8 a,u8 b);void OLED_Fill(u16 xstr,u8 ystr,u16 xend,u8 yend,u8 color);void OLED_ShowChinese(u8 x,u8 y,u8 *s,u8 sizey,u8 mode);void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode);void OLED_ShowString(u8 x,u8 y,u8 *dp,u8 sizey,u8 mode);u32 oled_pow(u8 m,u8 n);void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey,u8 mode);void OLED_DrawBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode);void OLED_DrawSingleBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode);void OLED_Init(void);void OLED_GPIO_Init(void);#endif
stm32的oled.c
#include "oledfont.h"#include "delay.h"#include "oled.h"#include "osal.h"#include "spi.h"#if OLED_USE_SOFT_SPIstatic void OLED_SCL_Clr(){ HAL_GPIO_WritePin(SOFT_SPI_SCK_GPIO_Port, SOFT_SPI_SCK_Pin, GPIO_PIN_RESET); //SCL}static void OLED_SCL_Set(){ HAL_GPIO_WritePin(SOFT_SPI_SCK_GPIO_Port, SOFT_SPI_SCK_Pin, GPIO_PIN_SET);}static void OLED_SDA_Clr(){ HAL_GPIO_WritePin(SOFT_SPI_MOSI_GPIO_Port, SOFT_SPI_MOSI_Pin, GPIO_PIN_RESET); //SDA}static void OLED_SDA_Set(){ HAL_GPIO_WritePin(SOFT_SPI_MOSI_GPIO_Port, SOFT_SPI_MOSI_Pin, GPIO_PIN_SET);}#endifstatic void OLED_RES_Clr(){ HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_RESET); //RES}static void OLED_RES_Set(){ HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_SET);}static void OLED_DC_Clr(){ HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET); //DC}static void OLED_DC_Set(){ HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_SET);}static void OLED_CS_Clr(){ HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_RESET); //CS}static void OLED_CS_Set(){ HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_SET);}static void OLED_Write_Byte(u8 dat){#if OLED_USE_SOFT_SPI u8 i; for(i=0;i<8;i++) { OLED_SCL_Clr(); //delay_us(200); if(dat&0x80) { OLED_SDA_Set(); } else { OLED_SDA_Clr(); } //delay_us(20); OLED_SCL_Set(); //delay_us(200); dat<<=1;}#else SPI_Write_Byte(2, dat); #endif}void OLED_WR_Bus(u8 dat){ OLED_CS_Clr(); OLED_Write_Byte(dat);OLED_CS_Set();}void OLED_WR_REG(u8 reg){ OLED_DC_Clr(); OLED_WR_Bus(reg); OLED_DC_Set(); }void OLED_WR_Byte(u8 dat){ OLED_WR_Bus(dat);}void Column_Address(u8 a,u8 b){ OLED_WR_REG(0x15);// Set Column Address OLED_WR_Byte(0x1c+a); OLED_WR_Byte(0x1c+b);}void Row_Address(u8 a,u8 b){ OLED_WR_REG(0x75);// Row Column Address OLED_WR_Byte(a); OLED_WR_Byte(b); OLED_WR_REG(0x5C); //写RAM命令}void OLED_Fill(u16 xstr,u8 ystr,u16 xend,u8 yend,u8 color){ u8 x,y; xstr/=4; xend/=4; Column_Address(xstr,xend-1); Row_Address(ystr,yend-1); for(x=xstr;x<xend;x++) { for(y=ystr;y<yend;y++) { OLED_WR_Byte(color); OLED_WR_Byte(color); } }}void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode){ u8 c,i,k,m,t=4,size2,data1,DATA=0; size2=(sizey/16+((sizey%16)?1:0))*sizey; c=chr-' '; Column_Address(x/4,x/4+sizey/8-1); Row_Address(y,y+sizey-1); for(i=0;i<size2;i++) { if(sizey==16) { data1=ascii_1608[c][i];//8x16 ASCII码 } else if(sizey==24) { data1=ascii_2412[c][i];//12x24 ASCII码 } else if(sizey==32) { data1=ascii_3216[c][i];//16x32 ASCII码 } if(sizey%16) { m=sizey/16+1; if(i%m) t=2; else t=4; } for(k=0;k<t;k++) { if(data1&(0x01<<(k*2+0))) { DATA=0xf0; } if(data1&(0x01<<(k*2+1))) { DATA|=0x0f; } if(mode) { OLED_WR_Byte(~DATA); }else { OLED_WR_Byte(DATA); } DATA=0; } }}void OLED_ShowString(u8 x,u8 y,u8 *dp,u8 sizey,u8 mode){ while(*dp!='\0') { OLED_ShowChar(x,y,*dp,sizey,mode); dp++; x+=sizey/2; }}u32 oled_pow(u8 m,u8 n){ u32 result=1; while(n--)result*=m; return result;}void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey,u8 mode){ u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(sizey/2)*t,y,' ',sizey,mode); continue; }else enshow=1; } OLED_ShowChar(x+(sizey/2)*t,y,temp+'0',sizey,mode); }}void OLED_DrawBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode){ u16 i,num; length=(length/4+((length%4)?1:0))*4; num=length/2*width; x/=4; length/=4; Column_Address(x,x+length-1); Row_Address(y,y+width-1); for(i=0;i<num;i++) { if(mode) { OLED_WR_Byte(~BMP[i]); }else { OLED_WR_Byte(BMP[i]); } }}void OLED_DrawSingleBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode){ u8 k,DATA=0; u16 i,num; length=(length/8+((length%8)?1:0))*8; num=length*width/8; x/=4; length/=4; Column_Address(x,x+length-1); Row_Address(y,y+width-1); for(i=0;i<num;i++) { for(k=0;k<4;k++) { if(BMP[i]&(0x01<<(k*2+0))) { DATA=0xf0; } if(BMP[i]&(0x01<<(k*2+1))) { DATA|=0x0f; } if(mode) { OLED_WR_Byte(~DATA); }else { OLED_WR_Byte(DATA); } DATA=0; } }}void OLED_Init(void){ OLED_RES_Clr(); delay_ms(10); OLED_RES_Set(); OLED_WR_REG(0xfd); /*Command Lock*/ OLED_WR_Byte(0x12); OLED_WR_REG(0xae); //Sleep In OLED_WR_REG(0xb3); //Set Display Clock Divide Ratio/Oscillator Frequency OLED_WR_Byte(0x91); OLED_WR_REG(0xca); //Set Multiplex Ratio OLED_WR_Byte(0x3f); OLED_WR_REG(0xa2); //Set Display Offset OLED_WR_Byte(0x00); // OLED_WR_REG(0xa1); //Set Display Start Line OLED_WR_Byte(0x00); // OLED_WR_REG(0xa0); //Set Re-Map $ Dual COM Line Mode if(USE_HORIZONTAL) { OLED_WR_Byte(0x14); } else { OLED_WR_Byte(0x06); } OLED_WR_REG(0xB5); //Set GPIO OLED_WR_Byte(0x00); OLED_WR_REG(0xab); //Function Selection OLED_WR_Byte(0x01); // OLED_WR_REG(0xb4); //Enable External VSL OLED_WR_Byte(0xa0); // OLED_WR_Byte(0xfd); // OLED_WR_REG(0xc1); //Set Contrast Current OLED_WR_Byte(0xff); OLED_WR_REG(0xc7); //Master Contrast Current Control OLED_WR_Byte(0x0f); // OLED_WR_REG(0xb9); //Select Default Linear Gray Scale Table OLED_WR_REG(0xb1); //Set Phase Length OLED_WR_Byte(0xe2); OLED_WR_REG(0xd1); //Enhance Driving Scheme Capability OLED_WR_Byte(0x82); OLED_WR_Byte(0x20); OLED_WR_REG(0xbb); //Set Pre-Charge Voltage OLED_WR_Byte(0x1f); OLED_WR_REG(0xb6); //Set Second Pre-Charge Period OLED_WR_Byte(0x08); OLED_WR_REG(0xbe); //Set VCOMH Deselect Level OLED_WR_Byte(0x07); OLED_WR_REG(0xa6); //Set Display Mode OLED_Fill(0,0,256,64,0x00); //Clear Screen OLED_WR_REG(0xaf); //Sleep Out LOG_INFO("oled init done");}void OLED_GPIO_Init(void){ GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(OLED_CS_GPIO_Port, OLED_CS_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(OLED_DC_GPIO_Port, OLED_DC_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(OLED_RES_GPIO_Port, OLED_RES_Pin, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */#if OLED_USE_SOFT_SPI HAL_GPIO_WritePin(GPIOF, SOFT_SPI_MOSI_Pin|SOFT_SPI_SCK_Pin, GPIO_PIN_RESET);#endif /*Configure GPIO pins : OLED_CS_Pin OLED_DC_Pin OLED_RES_Pin */ GPIO_InitStruct.Pin = OLED_CS_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(OLED_CS_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OLED_DC_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(OLED_DC_GPIO_Port, &GPIO_InitStruct); GPIO_InitStruct.Pin = OLED_RES_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(OLED_RES_GPIO_Port, &GPIO_InitStruct);#if OLED_USE_SOFT_SPI /*Configure GPIO pins : OLED_CS_Pin OLED_DC_Pin OLED_RES_Pin */ GPIO_InitStruct.Pin = SOFT_SPI_MOSI_Pin | SOFT_SPI_SCK_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = SOFT_SPI_MISO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);#endif}
分析OLED的LOG,发现只需要更改RES, DC, CS的GPIO控制即可。将OLED的GPIO控制由STM32 HAL库控制更改为MM32F5270 HAL控制,修改代码如下:
MM32F5270的oled.h
#ifndef __OLED_H#define __OLED_H #include "type_def.h"#define USE_HORIZONTAL 1 //设置显示方向 0:正向显示;1:旋转180度显示#define OLED_USE_SOFT_SPI 0void OLED_control_gpio_init(void);void OLED_WR_REG(u8 reg);void OLED_WR_Byte(u8 dat);void Column_Address(u8 a,u8 b);void Row_Address(u8 a,u8 b);void OLED_Fill(u16 xstr,u8 ystr,u16 xend,u8 yend,u8 color);void OLED_ShowChinese(u8 x,u8 y,u8 *s,u8 sizey,u8 mode);void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode);void OLED_ShowString(u8 x,u8 y,u8 *dp,u8 sizey,u8 mode);u32 oled_pow(u8 m,u8 n);void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey,u8 mode);void OLED_DrawBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode);void OLED_DrawSingleBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode);void OLED_Init(void);#endif
MM32F5270的oled.c
#include "oledfont.h"#include "delay.h"#include "oled.h"#include "demo_spi.h"#include "hal_rcc.h"#include "hal_gpio.h"#include "stdio.h"~~*void OLEDcontrolgpioinit(void){ //GPIOA RCCEnableAHB1Periphs(RCCAHB1PERIPHGPIOA, true); RCCResetAHB1Periphs(RCCAHB1PERIPHGPIOA);#if OLEDUSESOFTSPI RCCEnableAHB1Periphs(RCCAHB1PERIPHGPIOC, true); RCCResetAHB1Periphs(RCCAHB1PERIPHGPIOC);#endif GPIOInitType gpioinit; //RES PA10 gpioinit.Pins = GPIOPIN10; gpioinit.PinMode = GPIOPinModeOutPushPull; gpioinit.Speed = GPIOSpeed50MHz; GPIOInit(GPIOA, &gpioinit); //DC PA12 gpioinit.Pins = GPIOPIN12; gpioinit.PinMode = GPIOPinModeOutPushPull; gpioinit.Speed = GPIOSpeed50MHz; GPIOInit(GPIOA, &gpioinit); //CS PA15 gpioinit.Pins = GPIOPIN15; gpioinit.PinMode = GPIOPinModeOutPushPull; gpioinit.Speed = GPIOSpeed50MHz; GPIOInit(GPIOA, &gpioinit);#if OLEDUSESOFTSPI //soft SCL PC10 gpioinit.Pins = GPIOPIN10; gpioinit.PinMode = GPIOPinModeOutPushPull; gpioinit.Speed = GPIOSpeed50MHz; GPIOInit(GPIOC, &gpioinit); //soft MOSI PC12 gpioinit.Pins = GPIOPIN12; gpioinit.PinMode = GPIOPinModeOutPushPull; gpioinit.Speed = GPIOSpeed50MHz; GPIOInit(GPIOC, &gpioinit);#endif}#if OLEDUSESOFTSPIstatic void OLEDSOFTSPISCKClr(){ GPIOWriteBit(GPIOC, GPIOPIN10, 0u); //RES}static void OLEDSOFTSPISCKSet(){ GPIOWriteBit(GPIOC, GPIOPIN10, 1u); //RES}static void OLEDSOFTSPISDAClr(){ GPIOWriteBit(GPIOC, GPIOPIN12, 0u); //RES}static void OLEDSOFTSPISDASet(){ GPIOWriteBit(GPIOC, GPIOPIN12, 1u); //RES}#endifstatic void OLEDRESClr(){ GPIOWriteBit(GPIOA, GPIOPIN10, 0u); //RES}static void OLEDRESSet(){ GPIOWriteBit(GPIOA, GPIOPIN10, 1u); //RES}static void OLEDDCClr(){ GPIOWriteBit(GPIOA, GPIOPIN12, 0u); //RES}static void OLEDDCSet(){ GPIOWriteBit(GPIOA, GPIOPIN12, 1u); //RES}static void OLEDCSClr(){ GPIOWriteBit(GPIOA, GPIOPIN15, 0u); //RES}*~~static void OLED_CS_Set(){ GPIO_WriteBit(GPIOA, GPIO_PIN_15, 1u); //RES}static void OLED_Write_Byte(u8 dat){#if OLED_USE_SOFT_SPI u8 i; for(i=0;i<8;i++) { OLED_SOFT_SPI_SCK_Clr(); //delay_us(20); if(dat&0x80) { OLED_SOFT_SPI_SDA_Set(); } else { OLED_SOFT_SPI_SDA_Clr(); } //delay_us(20); OLED_SOFT_SPI_SCK_Set(); //delay_us(200); dat<<=1;}#else spi3_putbyte(dat);#endif}void OLED_WR_Bus(u8 dat){ OLED_CS_Clr(); OLED_Write_Byte(dat); OLED_CS_Set();}void OLED_WR_REG(u8 reg){ OLED_DC_Clr();OLED_WR_Bus(reg); OLED_DC_Set(); }void OLED_WR_Byte(u8 dat){ OLED_WR_Bus(dat);}void Column_Address(u8 a,u8 b){ OLED_WR_REG(0x15);// Set Column Address OLED_WR_Byte(0x1c+a); OLED_WR_Byte(0x1c+b);}void Row_Address(u8 a,u8 b){ OLED_WR_REG(0x75);// Row Column Address OLED_WR_Byte(a); OLED_WR_Byte(b); OLED_WR_REG(0x5C); //写RAM命令}void OLED_Fill(u16 xstr,u8 ystr,u16 xend,u8 yend,u8 color){ u8 x,y; xstr/=4; xend/=4; Column_Address(xstr,xend-1); Row_Address(ystr,yend-1); for(x=xstr;x<xend;x++) { for(y=ystr;y<yend;y++) { OLED_WR_Byte(color); OLED_WR_Byte(color); } }}void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey,u8 mode){ u8 c,i,k,m,t=4,size2,data1,DATA=0; size2=(sizey/16+((sizey%16)?1:0))*sizey; c=chr-' '; Column_Address(x/4,x/4+sizey/8-1); Row_Address(y,y+sizey-1); for(i=0;i<size2;i++) { if(sizey==16) { data1=ascii_1608[c][i];//8x16 ASCII码 } else if(sizey==24) { data1=ascii_2412[c][i];//12x24 ASCII码 } else if(sizey==32) { data1=ascii_3216[c][i];//16x32 ASCII码 } if(sizey%16) { m=sizey/16+1; if(i%m) t=2; else t=4; } for(k=0;k<t;k++) { if(data1&(0x01<<(k*2+0))) { DATA=0xf0; } if(data1&(0x01<<(k*2+1))) { DATA|=0x0f; } if(mode) { OLED_WR_Byte(~DATA); }else { OLED_WR_Byte(DATA); } DATA=0; } }}void OLED_ShowString(u8 x,u8 y,u8 *dp,u8 sizey,u8 mode){ while(*dp!='\0') { OLED_ShowChar(x,y,*dp,sizey,mode); dp++; x+=sizey/2; }}u32 oled_pow(u8 m,u8 n){ u32 result=1; while(n--)result*=m; return result;}void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey,u8 mode){ u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(sizey/2)*t,y,' ',sizey,mode); continue; }else enshow=1; } OLED_ShowChar(x+(sizey/2)*t,y,temp+'0',sizey,mode); }}void OLED_DrawBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode){ u16 i,num; length=(length/4+((length%4)?1:0))*4; num=length/2*width; x/=4; length/=4; Column_Address(x,x+length-1); Row_Address(y,y+width-1); for(i=0;i<num;i++) { if(mode) { OLED_WR_Byte(~BMP[i]); }else { OLED_WR_Byte(BMP[i]); } }}void OLED_DrawSingleBMP(u8 x,u8 y,u16 length,u8 width,const u8 BMP[],u8 mode){ u8 k,DATA=0; u16 i,num; length=(length/8+((length%8)?1:0))*8; num=length*width/8; x/=4; length/=4; Column_Address(x,x+length-1); Row_Address(y,y+width-1); for(i=0;i<num;i++) { for(k=0;k<4;k++) { if(BMP[i]&(0x01<<(k*2+0))) { DATA=0xf0; } if(BMP[i]&(0x01<<(k*2+1))) { DATA|=0x0f; } if(mode) { OLED_WR_Byte(~DATA); }else { OLED_WR_Byte(DATA); } DATA=0; } }}void OLED_Init(void){ OLED_RES_Clr(); delay_ms(10); OLED_RES_Set(); OLED_WR_REG(0xfd); /*Command Lock*/ OLED_WR_Byte(0x12); OLED_WR_REG(0xae); //Sleep In OLED_WR_REG(0xb3); //Set Display Clock Divide Ratio/Oscillator Frequency OLED_WR_Byte(0x91); OLED_WR_REG(0xca); //Set Multiplex Ratio OLED_WR_Byte(0x3f); OLED_WR_REG(0xa2); //Set Display Offset OLED_WR_Byte(0x00); // OLED_WR_REG(0xa1); //Set Display Start Line OLED_WR_Byte(0x00); // OLED_WR_REG(0xa0); //Set Re-Map $ Dual COM Line Mode if(USE_HORIZONTAL) { OLED_WR_Byte(0x14); } else { OLED_WR_Byte(0x06); } OLED_WR_REG(0xB5); //Set GPIO OLED_WR_Byte(0x00); OLED_WR_REG(0xab); //Function Selection OLED_WR_Byte(0x01); // OLED_WR_REG(0xb4); //Enable External VSL OLED_WR_Byte(0xa0); // OLED_WR_Byte(0xfd); // OLED_WR_REG(0xc1); //Set Contrast Current OLED_WR_Byte(0xff); OLED_WR_REG(0xc7); //Master Contrast Current Control OLED_WR_Byte(0x0f); // OLED_WR_REG(0xb9); //Select Default Linear Gray Scale Table OLED_WR_REG(0xb1); //Set Phase Length OLED_WR_Byte(0xe2); OLED_WR_REG(0xd1); //Enhance Driving Scheme Capability OLED_WR_Byte(0x82); OLED_WR_Byte(0x20); OLED_WR_REG(0xbb); //Set Pre-Charge Voltage OLED_WR_Byte(0x1f); OLED_WR_REG(0xb6); //Set Second Pre-Charge Period OLED_WR_Byte(0x08); OLED_WR_REG(0xbe); //Set VCOMH Deselect Level OLED_WR_Byte(0x07); OLED_WR_REG(0xa6); //Set Display Mode OLED_Fill(0,0,256,64,0x00); //Clear Screen OLED_WR_REG(0xaf); //Sleep Out printf("oled init done\n");}
对应只需要改动几个控制GPIO的具体实现,可以非常快速的进行移植
-
最后放上main函数,在main函数里要对用到的各个硬件做初始化,代码如下:
/*
* Copyright 2021 MindMotion Microelectronics Co., Ltd.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/#include
#include
#include “clock_init.h”
#include “demo_uart.h”
#include “conv_timer.h”
#include “demo_spi.h”
#include “led.h”
#include “delay.h”
#include “oled.h”
/*
* Functions.
*/int main(void)
{
BOARD_InitBootClocks();
timer1_init();
uart1_init();
#if !OLED_USE_SOFT_SPI
spi3_init();
#endif
led_init();OLED_control_gpio_init();
OLED_Init();
//OLED_ShowString(0, 0, “hello world”, 16, 0);
printf(“\r\ntim_basic example.\r\n”);timer1_start();
led_off(LED4);
led_off(LED5);while (1)
{
//spi3_putbyte(0xaa);
led_on(LED4);
delay_1ms();
led_off(LED4);
delay_1ms();
OLED_ShowString(0, 0, " ARM STAR-MC1 MM32F5270", 16, 0);
OLED_ShowString(0, 16, " aijishu", 16, 0);
OLED_ShowString(0, 32, “https://aijishu.com”, 16, 0);}
}/* EOF. */
显示效果如图所示:
四 总结
MindSDK已经提供了封装良好的驱动代码,能够非常方便的做开发,对于STM32平台的应用,能够非常快速的进行移植,所需要的工作量非常小。
STM32CubeMX只是提供了一个可视化的配置界面,但是其生成的代码对于一些比较大型的项目来说,其组织形式和代码复用性相比MindSDK并不会有优势。
MindSDK目前提供的轮子,已经能够应付一些基本需求。但是目前,MindSDK缺乏对FreeRTOS,RTThread等RTOS的支持。如果官方能够解决RTOS的问题,相信我们能够基于MindSDK用MM32F5230作出更多有趣的应用。
五 参考链接
【灵动官网】PLUS-F5270开发板介绍(含资料链接):https://www.mindmotion.com.cn…
【灵动官网】MM32F5270芯片介绍(含资料链接):https://www.mindmotion.com.cn…
【极术社区】基于灵动MM32F5系列芯片的PLUS-F5270开发板资料(包含逐飞科技网盘链接):https://aijishu.com/a/1060000…
【极术社区】[MM32F5270开发板试用] 基本开发环境搭建篇:https://aijishu.com/a/1060000…
【极术社区】带灵动微MM32F5的Plus-F5270开发板怎么玩?https://aijishu.com/a/1060000…