microSD card에서 first bootloader가 partition1, 2에 저장하여 select하여 사용하는 것과 같이 mmcblk1boot0, mmcblk1boot1에 copy후 select 하여 사용한다. 그리고 그다음은 partition1(fip)로 넘어가도록 설정한다.
stm32mpu Major ecosystem releases version : v3.0.0
kernel : Linux® kernel v5.10 (LTS)
-Working path
$ pwd
~/STM/Developer-Package
1. Kernel build
- 압축 풀기 및 패치
$ tar -xvf en.SOURCES-kernel-stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31.tar.xz
$ cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.10.10-r0
$ tar -xvf linux-5.10.10.tar.xz
$ cd linux-5.10.10
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
$ make ARCH=arm multi_v7_defconfig "fragment*.config"
$ for f in `ls -1 ../fragment*.config`; do scripts/kconfig/merge_config.sh -m -r .config $f; done
$ yes '' | make ARCH=arm oldconfig
$ tar -xvf en.SDK-x86_64-stm32mp1-openstlinux-20-02-19.tar.xz
$ cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31/sdk/
$ ./st-image-weston-openstlinux-weston-stm32mp1-x86_64-toolchain-3.1-openstlinux-5.10-dunfell-mp1-21-03-31.sh -d ../../SDK
3. tf-a(fwconfig, bl32) build
- 압축 풀기 및 패치
$ tar -xvf en.SOURCES-tf-a-stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31.tar.xz
$ cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31/sources/arm-ostl-linux-gnueabi/tf-a-stm32mp-2.4.r1-r0
$ tar -xvf tf-a-stm32mp-2.4.r1-r0.tar.gz
$ cd tf-a-stm32mp-2.4.r1
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
- 소스 변경 및 추가
$ vi ../Makefile.sdk
$ # Makefile.sdk에 stm32mp157f-whatmam-ev1 추가
$ cp -rfvp fdts/stm32mp157f-ev1.dts fdts/stm32mp157f-whatmam-ev1.dts
$ cp -rfvp fdts/stm32mp157f-ev1-fw-config.dts fdts/stm32mp157f-whatmam-ev1-fw-config.dts
$ # stm32mp157f-whatmam-ev1 dtb 추가
- Makefile.sdk 사용
$ source ~/STM/Developer-Package/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
$ export DEPLOYDIR=$PWD/../../FIP_artifacts/arm-trusted-firmware
$ make -f $PWD/../Makefile.sdk clean
$ make -f $PWD/../Makefile.sdk TF_A_DEVICETREE=stm32mp157f-whatmam-ev1 TF_A_CONFIG=trusted ELF_DEBUG_ENABLE='1' stm32
$ cd ~/STM/Developer-Package
$ tar -xvf en.SOURCES-u-boot-stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31.tar.xz
$ cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.10.r1-r0
$ tar -xvf u-boot-stm32mp-2020.10.r1-r0.tar.gz
$ cd u-boot-stm32mp-2020.10.r1
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
- 소스 변경 및 추가
$ vi ../Makefile.sdk
$ vi arch/arm/dts/Makefile
$ # Makefile.sdk에 stm32mp157f-whatmam-ev1 추가
$ cp -rfvp arch/arm/dts/stm32mp157f-ev1.dts arch/arm/dts/stm32mp157f-whatmam-ev1.dts
$ cp -rfvp arch/arm/dts/stm32mp157f-ev1-u-boot.dtsi arch/arm/dts/stm32mp157f-whatmam-ev1-u-boot.dtsi
$ # *-u-boot.dtsi 없으면 빌드는 되나, 부팅이 안됨.
$ # dtb model명 변경하여 디버그에서 변경 되는지 확인 하도록 수정
- Makefile.sdk 사용
$ source ~/STM/Developer-Package/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
$ export DEPLOYDIR=$PWD/../../FIP_artifacts/u-boot
$ make -f $PWD/../Makefile.sdk clean
$ make -f $PWD/../Makefile.sdk UBOOT_CONFIGS=stm32mp15_trusted_defconfig,trusted,u-boot.dtb DEVICE_TREE="stm32mp157f-whatmam-ev1" uboot
아래와 같은 make 실행하여 .config 생성된 상태라면 make mrproper 꼭 해줘야 한다.
- Makefile 사용
$ make stm32mp15_trusted_defconfig
$ make DEVICE_TREE=stm32mp157f-ev1 all
> Makefile.sdk 사용 시 하지 않아도 된다.
5. optee build
- 압축 풀기 및 패치
$ cd ~/STM/Developer-Package
$ tar -xvf en.SOURCES-optee-stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31.tar.xz
$ cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-03-31/sources/arm-ostl-linux-gnueabi/optee-os-stm32mp-3.12.0.r1-r0
$ tar -xvf optee-os-stm32mp-3.12.0.r1-r0.tar.gz
$ cd optee-os-stm32mp-3.12.0.r1
$ for p in `ls -1 ../*.patch`; do patch -p1 < $p; done
- 소스 변경 및 추가
$ vi ../Makefile.sdk
$ # Makefile.sdk에 stm32mp157f-whatmam-ev1 추가
$ cp -rfvp core/arch/arm/dts/stm32mp157f-ev1.dts core/arch/arm/dts/stm32mp157f-whatmam-ev1.dts
- Makefile.sdk 사용
$ source ~/STM/Developer-Package/SDK/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
$ export DEPLOYDIR=$PWD/../../FIP_artifacts/optee
$ make -f $PWD/../Makefile.sdk clean
$ make -f $PWD/../Makefile.sdk CFG_EMBED_DTB_SOURCE_FILE=stm32mp157f-whatmam-ev1 optee
RS는 Instruction mode OR Data mode, E는 Enable 등.. 인걸 알 수 있다.
2. DataSheet를 본다 - 타이밍
1. R/W : High, E : Low 2. RS : High or Low 3. R/W : High -> Low ------- 40nSec이상 delay 4. E : Low -> High ------- 150nSec이상 delay 5. Data Bus ------- 80nSec이상 delay 6. E : High -> Low ------- 10nSec이상 delay
데이터시트를 보면 Max가 없기에 Critical하게 꼭 맞춰줄 필요는 없어 보인다.
이러한 최소한의 딜레이가 필요하다. 그렇지 않으면 원하는 값으로 이루어지지 않음. Read mode에서는 RW쪽만 다르다.
3. Instructions 해석
Note : Fiunction Set 5x11 dots는 4BIT일 경우만 사용 가능하다. 현재는 8bit,2-line,5x8로 set
그리고 실제 LCD는 5x7처럼 보이는데 커서가 1을 차지하여 5x8이다.
또한 Instruction후 딜레이 필요.
AND DDRAM은 DB7은 항상 set이여서 시작주소가 0x80이다. 1-Line과 2-Line이 bit수와 주소가 다르다.
#include "avr/io.h"
#include "avr/iom128.h"
#include "util/delay.h"
/*
RS : Instruction mode VS Data mode?
(LCD_controller VS LCD_data)
E : Enable
*/
void LCD_controller(unsigned char control)
{
_delay_ms(40);
PORTG = 0x00; // clear.
_delay_us(0.04); //RW & RS Setup time is 40ns min.
PORTG |= 0x01; // G set. Enable
_delay_us(0.15); //Data Setup time is 80ns min.
PORTA = control; // Data input.
_delay_us(0.08); // valid data is 130ns min.
PORTG = 0x0;// RS set. RW set. G clear.
_delay_us(0.01);
}
void LCD_data(unsigned char Data)
{
_delay_ms(1);
PORTG = 0x04; //RS set. RW clear. G clear.
_delay_us(0.04); //RW & RS Setup time is 40ns min.
PORTG = 0x05; // E set.
_delay_us(0.15); //Data Setup time is 80ns min.
PORTA = Data; // Data input.
_delay_us(0.08); // valid data min is 130ns.
PORTG = 0x0; // RS clear. RW set. G clear.
_delay_us(0.01);
}
void LCD_string(unsigned char address, unsigned char *ptr)
{
int i=0;
LCD_controller(address); // LCD display start position
while(*ptr)
{
if(address+i == 0x90)
LCD_controller(0xc0); // second line display
LCD_data(*ptr);
i++;
ptr++;
}
}
void LCD_initialize(void)
{
/* 8bit interface mode */
LCD_controller(0x38); // Function set. Use 2-line, display on.
_delay_us(40); // wait for more than 39us.
LCD_controller(0x0f); // Display ON/OFF Control. display,cursor,blink on
_delay_us(40); // wait for more than 39us.
LCD_controller(0x01); // Display Clear.
_delay_ms(1.53); // wait for more than 1.53ms.
LCD_controller(0x06); // Entry Mode Set. I/D increment mode, entire shift off
}
int main()
{
DDRG = 0x07; // Control_bit
DDRA = 0xff; // Data_bit
LCD_initialize();
LCD_string(0x80, "Hello World!!!! LCD TEST..12345678987654321"); // Start address is 0x80(0,0)
while(1)
{
/*
LCD_controller(0x1c);//화면 그대로 right
LCD_controller(0x18);//화면 그대로 left
_delay_ms(5000);
*/
}
return 0;
}