页次: 1
一般是双缓冲大小不对引起的。
需要调试可企鹅 415855548 V同号
D1s芯片都没得买。是不是停产了
https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-24100641678.11.618b1e53cIchFu&id=658215313702
怎么会买不到
拿到了D1的板板
为了文件系统捣鼓起来更方便和各种OTA操作的舒服感觉,需要搞上overlayfs, 查看了启动Log需要调用mkfs.ext4,
所以,搞上了e2fsprogs
make menuconfig 一阵操作后,竟然报错了,还好有谷歌大法,直接找到问题:
https://bugs.gentoo.org/577946
于是自己加了个patch进去,一波烧录,起飞了
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/root 99884 49024 43692 53% /rom
devtmpfs 503912 0 503912 0% /dev
tmpfs 508104 36 508068 0% /tmp
/dev/by-name/rootfs_data
11367 149 10962 1% /overlay
overlayfs:/overlay 11367 149 10962 1% /
/dev/by-name/UDISK 6950068 15832 6917852 0% /mnt/UDISK
不敢独享,patch放到附件了,另外附上分区信息设置文件 和 fstab
e2fsprogs编译通过和磁盘分区fex_20220128-2315.zip
patch文件 直接扔到 package\utils\e2fsprogs\patches 下面就可以啦。
fstab 是在目录tina_d1_open_v1.0.1\target\allwinner\d1-nezha\base-files\etc\config
sys_partition.fex 是在目录 tina_d1_open_v1.0.1\device\config\chips\d1\configs\nezha
当然menuconfig 要选上e2sfprogs
如题
因为不喜欢插拔卡搞来搞去,喜欢直接USB插上直接干活烧录到底,
那就,看下D1怎么搞TF直接通过PhoenixSuit烧录 TF卡或者SDNAND
第一步,看启动过程的LOG:
U-Boot 2018.05-g0a62f10 (Dec 31 2021 - 07:53:57 +0000) Allwinner Technology
[03.820]DRAM: 512 MiB
[03.825]Relocation Offset is: 1def0000
[03.847]secure enable bit: 0
[03.851]CPU=1008 MHz,PLL6=600 Mhz,AHB=200 Mhz, APB1=100Mhz MBus=300Mhz
[03.858]flash init start
[03.860]workmode = 16,storage type = 0
try card 2
set card number 2
get card number 2
[03.867][mmc]: mmc driver ver uboot2018:2021-04-16 14:23:00-1
[03.876][mmc]: get sdc_type fail and use default host:tm4.
[03.900][mmc]: Is not Boot mode!
[03.903][mmc]: SUNXI SDMMC Controller Version:0x50310
[03.914][mmc]: ************Try SD card 2************
[03.919][mmc]: mmc 2 cmd timeout 100 status 100
[03.924][mmc]: smc 2 err, cmd 8, RTO
[03.927][mmc]: mmc 2 close bus gating and reset
[03.932][mmc]: mmc 2 cmd timeout 100 status 100
[03.936][mmc]: smc 2 err, cmd 55, RTO
[03.940][mmc]: mmc 2 close bus gating and reset
[03.944][mmc]: ************Try MMC card 2************
[03.953][mmc]: mmc 2 cmd timeout 100 status 100
[03.957][mmc]: smc 2 err, cmd 1, RTO
[03.960][mmc]: mmc 2 close bus gating and reset
[03.965][mmc]: Card did not respond to voltage select!
[03.969][mmc]: ************SD/MMC 2 init error!************
[03.975][mmc]: mmc init product failed
MMC init failed
try emmc fail
[03.988]sunxi-spinand: AW SPINand MTD Layer Version: 1.5 20200407
[03.994]sunxi-spinand-phy: AW SPINand Phy Layer Version: 1.9 20200306
[04.041]sunxi-spinand-phy: request spi0 gpio ok
[04.045]sunxi-spinand-phy: request general tx dma channel ok!
[04.050]sunxi-spinand-phy: request general rx dma channel ok!
[04.056]sunxi-spinand-phy: set spic0 clk to 20 Mhz
[04.060]sunxi-spinand-phy: init spic0 clk ok
[04.085]sunxi-spinand-phy: read id failed : -110
try nand fail
[04.132]unrecognized JEDEC id bytes: ff, ff, ff
try spinor fail
initcall sequence 000000005ff948c8 failed at call 000000004200d70e (err=-1)
### ERROR ### Please RESET the board ###
看到关键的点
try card 2
set card number 2
get card number 2
这里默认从card 2 开始
那么咱就先试试看,直接从card 0 行不行?
直接搜索到代码中定位到的是:
tina_d1_open_v1.0.1\lichee\brandy-2.0\u-boot-2018\drivers\sunxi_flash\mmc\sdmmc.c
中的接口:
int sunxi_sprite_mmc_probe(void)
{
#ifndef CONFIG_MACH_SUN50IW11
return sdmmc_init_for_sprite(0, 2);
#else
int workmode = uboot_spare_head.boot_data.work_mode;
if (workmode == WORK_MODE_CARD_PRODUCT)
return -1;
else
return sdmmc_init_for_sprite(0, 0);
#endif
}
这里 CONFIG_MACH_SUN50IW11 没有定义
默认是执行 return sdmmc_init_for_sprite(0, 2);
那么咱就是说,直接改return sdmmc_init_for_sprite(0, 0); 试试看?
好的说改就改了。
int sunxi_sprite_mmc_probe(void)
{
#ifndef CONFIG_MACH_SUN50IW11
return sdmmc_init_for_sprite(0, 0);
#else
int workmode = uboot_spare_head.boot_data.work_mode;
if (workmode == WORK_MODE_CARD_PRODUCT)
return -1;
else
return sdmmc_init_for_sprite(0, 0);
#endif
}
改动了下,直接烧录测一下:
U-Boot 2018.05-g0a62f10-dirty (Jan 28 2022 - 22:35:17 +0800) Allwinner Technology
[03.804]DRAM: 512 MiB
[03.809]Relocation Offset is: 1def0000
[03.831]secure enable bit: 0
[03.835]CPU=1008 MHz,PLL6=600 Mhz,AHB=200 Mhz, APB1=100Mhz MBus=300Mhz
[03.842]flash init start
[03.844]workmode = 16,storage type = 0
running in sunxi_sprite_mmc_probe try card
sdmmc_init_for_sprite try card 0
set card number 0
get card number 0
[03.857][mmc]: mmc driver ver uboot2018:2021-04-16 14:23:00-1
[03.866][mmc]: get sdc_type fail and use default host:tm1.
[03.891][mmc]: can't find node "mmc0",will add new node
[03.896][mmc]: fdt err returned <no error>
[03.900][mmc]: Using default timing para
[03.904][mmc]: SUNXI SDMMC Controller Version:0x50310
[03.922][mmc]: card_caps:0x3000000a
[03.925][mmc]: host_caps:0x3000003f
[03.933]Loading Environment from SUNXI_FLASH... OK
[03.939]try to burn key
[03.943]out of usb burn from boot: not need burn key
Hit any key to stop autoboot: 0
sunxi work mode=0x10
run usb efex
delay time 2500
weak:otg_phy_config
usb init ok
set address 0x30
set address 0x30 ok
set address 0x31
set address 0x31 ok
SUNXI_EFEX_ERASE_TAG
erase_flag = 0x12
origin_erase_flag = 0x1
FEX_CMD_fes_verify_status
FEX_CMD_fes_verify last err=0
the 0 mbr table is ok
the 1 mbr table is ok
the 2 mbr table is ok
the 3 mbr table is ok
*************MBR DUMP***************
total mbr part 9
part[0] name :boot-resource
part[0] classname :DISK
part[0] addrlo :0x1f8
part[0] lenlo :0x1f80
part[0] user_type :32768
part[0] keydata :0
part[0] ro :0
part[1] name :env
part[1] classname :DISK
part[1] addrlo :0x2178
part[1] lenlo :0x1f8
part[1] user_type :32768
part[1] keydata :0
part[1] ro :0
part[2] name :env-redund
part[2] classname :DISK
part[2] addrlo :0x2370
part[2] lenlo :0x1f8
part[2] user_type :32768
part[2] keydata :0
part[2] ro :0
part[3] name :boot
part[3] classname :DISK
part[3] addrlo :0x2568
part[3] lenlo :0x50b8
part[3] user_type :32768
part[3] keydata :0
part[3] ro :0
part[4] name :dsp0
part[4] classname :DISK
part[4] addrlo :0x7620
part[4] lenlo :0x3f0
part[4] user_type :32768
part[4] keydata :0
part[4] ro :0
part[5] name :recovery
part[5] classname :DISK
part[5] addrlo :0x7a10
part[5] lenlo :0x6e40
part[5] user_type :32768
part[5] keydata :0
part[5] ro :0
part[6] name :rootfs
part[6] classname :DISK
part[6] addrlo :0xe850
part[6] lenlo :0x1000000
part[6] user_type :32768
part[6] keydata :0
part[6] ro :0
part[7] name :rootfs_data
part[7] classname :DISK
part[7] addrlo :0x100e850
part[7] lenlo :0x6400
part[7] user_type :32768
part[7] keydata :0
part[7] ro :0
part[8] name :UDISK
part[8] classname :DISK
part[8] addrlo :0x1014c50
part[8] lenlo :0x0
part[8] user_type :33024
part[8] keydata :0
part[8] ro :0
total part: 10
mbr 0, 1f8, 8000
boot-resource 1, 1f80, 8000
env 2, 1f8, 8000
env-redund 3, 1f8, 8000
boot 4, 50b8, 8000
dsp0 5, 3f0, 8000
recovery 6, 6e40, 8000
rootfs 7, 1000000, 8000
rootfs_data 8, 6400, 8000
UDISK 9, 0, 8100
[07.119]erase all part start
need erase flash: 18
[07.125][mmc]: mmc_mmc_erase: sd card don't support erase
[07.130]read item0 copy0
[07.132][mmc]: memalign dst_align is NULL!
read first backup failed in fun sunxi_sprite_mmc_secread line 468
[07.142][mmc]: memalign dst_align is NULL!
read first backup failed in fun sunxi_sprite_mmc_secread line 468
[07.152]unknown error happen in item 0 read
[07.155]get secure storage map err
[07.159][mmc]: memalign src_align is NULL!
write first backup failed in fun sunxi_sprite_mmc_secwrite line 533
[07.168]erase secure storage block 0 err
SUNXI_EFEX_MBR_TAG
mbr size = 0x10000
write primary GPT success
write Backup GPT success
[08.043]update partition map
FEX_CMD_fes_verify_status
FEX_CMD_fes_verify last err=0
running in sunxi_sprite_mmc_init try card 2
******Has init
FEX_CMD_fes_verify_value, start 0x1f8, size high 0x0:low 0x2f8c00
FEX_CMD_fes_verify_value 0x3481d9f0
FEX_CMD_fes_verify_value, start 0x2178, size high 0x0:low 0x20000
FEX_CMD_fes_verify_value 0xcb347ad3
FEX_CMD_fes_verify_value, start 0x2370, size high 0x0:low 0x20000
FEX_CMD_fes_verify_value 0xcb347ad3
FEX_CMD_fes_verify_value, start 0x2568, size high 0x0:low 0x91d000
FEX_CMD_fes_verify_value 0xe5a32b17
FEX_CMD_fes_verify_value, start 0x7620, size high 0x0:low 0x4059c
FEX_CMD_fes_verify_value 0x413a5c54
FEX_CMD_fes_verify_value, start 0xe850, size high 0x0:low 0x6400000
FEX_CMD_fes_verify_value 0x87284509
bootfile_mode=4
SUNXI_EFEX_BOOT1_TAG
boot1 size = 0xfc000, max size = 0x200000
uboot size = 0xfc000
storage type = 7
FEX_CMD_fes_verify_status
FEX_CMD_fes_verify last err=0
bootfile_mode=4
SUNXI_EFEX_BOOT0_TAG
boot0 size = 0x10000
[36.353][mmc]: write mmc 0 info ok
dram para[0] = 318
dram para[1] = 3
dram para[2] = 7b7bfb
dram para[3] = 1
dram para[4] = 10f210f2
dram para[5] = 4001000
dram para[6] = 1c70
dram para[7] = 42
dram para[8] = 18
dram para[9] = 0
dram para[10] = 4a2195
dram para[11] = 2423190
dram para[12] = 8b061
dram para[13] = b4787896
dram para[14] = 0
dram para[15] = 48484848
dram para[16] = 48
dram para[17] = 1620121e
dram para[18] = 0
dram para[19] = 0
dram para[20] = 0
dram para[21] = 870000
dram para[22] = 24
dram para[23] = b4056103
dram para[24] = 0
dram para[25] = 0
dram para[26] = 0
dram para[27] = 0
dram para[28] = 0
dram para[29] = 0
dram para[30] = 0
dram para[31] = 0
storage type = 7
FEX_CMD_fes_verify_status
FEX_CMD_fes_verify last err=0
sunxi_efex_next_action=2
exit usb
next work 2
▒[33]HELLO! BOOT0 is starting!T
[36]BOOT0 commit : 603490b
[38]set pll start
[40]periph0 has been enabled
[43]set pll end
[44][pmu]: bus read error
[47]board init ok
[49]DRAM only have internal ZQ!!
[52]get_pmu_exist() = -1
[54]DRAM BOOT DRIVE INFO: V0.24
[57]DRAM CLK = 792 MHz
[59]DRAM Type = 3 (2:DDR2,3:DDR3)
[62]DRAMC ZQ value: 0x7b7bfb
[65]DRAM ODT value: 0x42.
[67]ddr_efuse_type: 0x0
[70]DRAM SIZE =1024 M
[74]DRAM simple test OK.
[76]dram size =1024
[78]card no is 0
[79]sdcard 0 line count 4
[82][mmc]: mmc driver ver 2021-04-2 16:45
[91][mmc]: Wrong media type 0x0
[94][mmc]: ***Try SD card 0***
[103][mmc]: HSSDR52/SDR25 4 bit
[106][mmc]: 50000000 Hz
[108][mmc]: 15280 MB
[110][mmc]: ***SD/MMC 0 init OK!!!***
[158]Loading boot-pkg Succeed(index=0).
[162]Entry_name = opensbi
[165]Entry_name = u-boot
[169]Entry_name = dtb
[171]mmc not para
[173]Jump to second Boot.
23333 还真就烧录进去了,也不知道这会有什么隐患没,反正我用着很舒服,不用插拔卡了。若有啥隐患还请大佬们指正。
同时呢,这个烧录口USB还能做adb shell调试用,美滋滋了。
而且呢额外挂载的 /mnt/SDCARD 空间等可以在烧录后保留,不会被擦除。
芜湖,起飞!
@TeveT
可以搞个简单的视频教程吗,手残党好难受
大佬,你要的教程我整了
内存植锡练手,给全志D1开发板换1GB内存 https://b23.tv/MNjIy5l
刚整了个d1的开发板玩玩,刷了debian试了下,感觉启动好慢,
另外,内存512感觉不是很舒适,刚好有废料板3288上有1GB内存,
换一下,顺便搞个植锡小过程,供没操作过bga的坑友尝尝鲜。
注意啊,这个没有任何的广告,锡膏钢网都很便宜,当然,风枪不便宜。
视频整上b站了
内存植锡练手,给全志D1开发板换1GB内存 https://b23.tv/MNjIy5l
对的这个帖子就是拉lvgl fb 改的,加入了你说的初始化部分,只是填坑
lvgl_v8.zip
8.0的,lv_driver替换的时候注意不要把文件覆盖了。
其实lvgl的git上面有linux的移植,基于frame buffer。只要把ssd20x的特定初始化部分添加上就可以。
如题,分享一下
sun8iw8p1-pinctrl.dtsi 添加:
key_pins: key_pins@0 {
allwinner,pins= "PB12";
allwinner,function = "gpio_in";
allwinner,muxsel = <0>;
allwinner,drive = <1>;
allwinner,pull = <1>;
};
board.dts 添加:
gpio_keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&key_pins>;
autorepeat;
button@1 {
label = "Key home";
linux,code = <158>;
gpios = <&pio 1 12 6 1 1 1>;
gpio-key,wakeup;
//interrupt-parent = <&pio>;
//interrupts = <1 12 IRQ_TYPE_EDGE_FALLING>; //PB12
};
};
好,接着奏乐,接着舞……
好滴,感谢分享,搞搞看
TeveT 说:咋说,awtk 本地编译有包吗,我弄来看看
duanchangstar 说:楼主很厉害啊,可以顺便搞一下AWTK的双缓冲吗
如题,没有固定MAC,没有绑定chipid,TXD烦死了,
很烦地看了一通代码,对比下ZETA
搞上:
sun8iw8p1.dtsi 中:
chipid: sunxi-chipid@1c23800 {
compatible = "allwinner,sunxi-chipid";
device_type = "chipid";
reg = <0x0 0x01c23800 0 0x0100>; /* chipid */
};
lichee\linux-4.9\drivers\net\ethernet\allwinner\sunxi-gmac.c 中:
extern int sunxi_get_soc_chipid(uint8_t *chip_id);
//#define sunxi_get_soc_chipid(x) {}
嗯,接着奏乐,接着舞。
我是整个板子连同他们设计的底板一起买的,那个板子没有问题。
如果是自己设计底板,当然是要小心对上。
与其说这个设计的GND和电源挨得太近, 不如说底板没设计好或者焊接出问题。
因为一旦GND和电源共死了,其他脚位也无法避免短路。
或者你说对手工焊接底板的爱好者不太友好也无可厚非。
TeveT 说:不不不不,
这不到1mm就算紧挨着?不至于不至于
你铺地铜间距也就8mil 10 mil 怎么不会短?
问题来了,你是怎么操作了呢,是直接下烙铁?
毕竟我的没有烧
另外固态硬盘也是m.2 意思是你也得烧几片么microxp 说:居然把vcc和gnd脚紧挨在一起,金手指那么细的线,间距不到1mm,一不小心就短路了,都烧了好几块了......
多方面可能,1.螺丝孔位置做的有点偏,导致固定之后板子斜了,2. 由于是2个m2座子,2个M2座子如果有安装偏差,也可能导致板子有点偏
大佬啊, EPHY_RTX 对地有个 6K 电阻,接没接。
荔枝派的zero plus,没有用官方提供的变压器+RJ45的接法,用的HR911105A,仿的这个帖子里的接法
https://whycan.com/t_3887.html
https://whycan.cn/files/members/1206/NanoPi-M1.jpg
看固件网卡运行正常,也能正常ifconfig up,但就是插上网线不通哦
咋调试呢,量了一下Link灯也不亮,link灯那个引脚有1.8v
是因为没有严格做那个100欧的差分线?我就随便画的差分线,算了下估计90欧左右,应该也能用吧
另外看索智S3和荔枝派的V3S都有一个PHY_RTX的引脚,荔枝派 plus就没有这个引脚,是不是这个原因
意思是你这个自己没有修改过TINA的boot, 直接就烧录了对吗?
我用的是V3S 的tina3.5, 是自己魔改,要看看代码。
TeveT 说:uboot烧录部分改对了没
无根浮萍 说:https://whycan.com/files/members/5755/2021-03-31_113740.png
果然只有一个分区,这是为什么呢?
请问应该怎么修改呢?我几乎翻越了所有tina文档,都木找到有。
uboot烧录部分改对了没
https://whycan.com/files/members/5755/2021-03-31_113740.png
果然只有一个分区,这是为什么呢?
参考我的这个: https://whycan.com/t_5305.html
大佬,bluez做蓝牙音箱要咋用,用pulseaudio,
搞晕了都
大佬另开个帖子呀,顶上去
在楼主的基础上增加rotation,开源了:
https://github.com/caszhao/ssd_lvgl
编译器和库的依赖路径要改一下,应该是没问题的。
dbus不适合嵌入式环境,在桌面也有点奇葩,估计是为了进程互操作和解藕吧。
我也想试一试,请问楼主这个代码可以在Ubuntu玩吗?
TeveT 说:主要就是不想花大时间弄dbus,既然拿出来单独用就分享一下,都是bluez的代码哈哈哈哈,嵌入自己的代码只要回调注册搞一搞,界面交互效率高
raspberryman 说:感谢楼主分享,我以前参考晕哥那个 btstack帖子搞了一个demo,后来没有玩了
郁闷,没有搞定 Ubuntu下用btstack协议栈驱动 RTL8723BS
http://whycan.com/t_1133.html#p53670咦,居然发现楼主也玩了 btstack...
没有玩btstack啦,那时候测试驱动包,
最后测试发现,蓝牙声音出问题是因为驱动打印log问题
感谢楼主分享,我以前参考晕哥那个 btstack帖子搞了一个demo,后来没有玩了
郁闷,没有搞定 Ubuntu下用btstack协议栈驱动 RTL8723BS
http://whycan.com/t_1133.html#p53670咦,居然发现楼主也玩了 btstack...
TeveT 说:对的,我直接拿这部分嵌入我的代码,做蓝牙播放器界面
奔跑的孩子 说:请问楼主 bluetoothctl 是bluez 的源码包里面的吗?
主要就是不想花大时间弄dbus,既然拿出来单独用就分享一下,都是bluez的代码哈哈哈哈,嵌入自己的代码只要回调注册搞一搞,界面交互效率高
感谢楼主分享,我以前参考晕哥那个 btstack帖子搞了一个demo,后来没有玩了
郁闷,没有搞定 Ubuntu下用btstack协议栈驱动 RTL8723BS
http://whycan.com/t_1133.html#p53670咦,居然发现楼主也玩了 btstack...
TeveT 说:对的,我直接拿这部分嵌入我的代码,做蓝牙播放器界面
奔跑的孩子 说:请问楼主 bluetoothctl 是bluez 的源码包里面的吗?
平台 V3S, TINA
基于C,玩弄bluez的时候总感觉要在代码里去使用bluez的agent极其蛋疼,又没怎么处理过dbus的东西,既然如此,拿现成工具搞起来? 好!
如果要直接新开进程bluetoothctl , 可以这样:
使用Local socket 去访问,用socketpair 到一个文件流节点,然后 vfork 出进程,用一个循环去读文件流节点,来取得bluetoothctl 的返回值,
代码如下:
void bluetooth_pthread(void)
{
int i = 0, ret,haveconnect = 0,sizeread = 0;
char * Connectedyes = NULL,* Pairedyes = NULL,* yesorno = NULL,*tt = NULL;
int fds[2];
pid_t pid;
unsigned char *datareadp = buf;
memset(buf,0,sizeof(buf));
char startbluetooth[128];
sprintf(startbluetooth, "/usr/bin/bluetoothctl\n");
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
return -1;
switch(pid=vfork()) {
case -1: /* Error */
close(fds[0]);
close(fds[1]);
return -1;
case 0: /* child */
close(fds[0]);
dup2(fds[1], 0);
dup2(fds[1], 1);
close(fds[1]);
execl("/bin/sh", "sh", "-c", startbluetooth, NULL);
//system(bluectl);
_exit(127);
}
/* parent */
close(fds[1]);
bluectl = fds[0];
bluesafe_write(bluectl,"power on\n",sizeof("power on\n"));//Changing power on succeeded
while(!blueQuit)
{
if((sizeread = read(bluectl,datareadp,4096))> 0)
{
printf("\nsizeread = %d\n", sizeread);
if(LoopBluetoothStateAndHandle(buf) == 0 )//处理你收到的bluetoothctl的返回数据
{
}
else
{
}
}
}
blueThreadId = 0;
close(bluectl);
}
啊这? 大写的蛋疼! 测试的时候还发现read 会断流,简直了还得处理断帧和粘帧? 不要啊!
好了,因为蛋疼所以倒腾。
直接抓了bluetoothctl 单独拿出来编译,这样你可以嵌入任何你自己的代码里,同时可以在代码里去控制bluetooth的任何状态。
这样可以更愉快地玩耍bluez 了,dbus还不用怎么操作, 如果大佬们有更好的办法,可以分享一下,那更感谢了。
当然,这个编译,只要你平台支持了bluez, 那换个平台也是OK的。
文件见附件:
mybluetoothctl.zip
感谢大佬分享,一步到位,
一体打包烧录固件:
ssd202-7inch-1024x600-spinand-20210302.7zu-boot 烧录指令:
setenv serverip 192.168.1.99;setenv ipaddr 192.168.1.33;nand erase 0x0 0x8000000;tftp 0x20000000 o/sysimage-nand.img;nand write 0x20000000 0x0 ${filesize};
官方烧录器烧录:
https://whycan.com/files/members/5985/2021-03-02_124657.png
高手,学习了
TeveT 说:嗯? 怎么理解呢,意思是,双缓冲下,在硬件disp控制器读帧过程中顿一下么, vsync机制是当前帧被使用的时候不会被填充么
达克罗德 说:光双缓冲,没有vsync处理,应该还是有小概率产生撕裂吧
就怕切缓冲buff地址时候,如果发生在读帧过程中,一样会导致画面撕裂。感觉和硬件设计和驱动程序有关,也许某些SOC硬件可以保证直接切换地址不会导致问题。
不过我看许多SOC都还是明确要求在帧中断去切缓冲。
DRM的文档有关于这个双缓冲和VSync的说明:
https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-double-buffered.c
https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset-vsync.cIf you run this example, you will notice that there is almost no flickering,
* anymore. The buffers are now swapped as a whole so each new frame shows
* always the whole new image. If you look carefully, you will notice that the
* modeset.c example showed many screen corruptions during redraw-cycles.
*
* However, this example is still not perfect. Imagine the display-controller is
* currently scanning out a new image and we call drmModeSetCrtc()
* simultaneously. It will then have the same effect as if we used a single
* buffer and we get some tearing. But, the chance that this happens is a lot
* less likely as with a single-buffer. This is because there is a long period
* between each frame called vertical-blank where the display-controller does
* not perform a scanout. If we swap the buffers in this period, we have the
* guarantee that there will be no tearing. See the modeset-vsync.c example if
* you want to know how you can guarantee that the swap takes place at a
* vertical-sync.根据这个理解,即使硬件支持任意切缓冲不会导致画面撕裂,也还是会有问题。当绘图刷新率不稳定的时候,有可能会导致掉帧现象。你可以想象在一帧的时间里,如果不在v-blank时间来切缓冲,有可能刚好错过当前这一帧的数据。所以PC游戏里一般有个选项,锁定帧刷新到显卡vsync
如题,上周末应晕哥邀请解决下小问题。
启明云端的群有挺多群友需要这个东西。硬件平台是7寸 1024x600 的ssd202 开发板,自带一个点菜系统的demo
这里直接打包发送网盘:
链接: https://pan.baidu.com/s/117lyj1uTXC-Rt66Co07wLA
提取码:fkk5
释放后在配置好交叉编译器的条件下可以直接make出来,可执行文件是 demossd
上传在这儿
几个细节注意下:
1、注意下我的代码的Makefile 依赖 SSD20X的源代码的project文件夹,
结构是这样的:
├── LVGL7.10-SSD202
│ ├── export-ssd20x-gcc.sh
│ ├── gcc-arm-8.2-2018.08-x86_64-arm-linux-gnueabihf
│ ├── linux_frame_buffer
├── project
2、释放出来代码后阅读下Makefile 或者修改一下自己的结构让它可以调用到project 的目录。
3 、另外ssd20x 这个平台比较不一样, 使用fb之前要配置硬件信息,
我是无脑直接搬运来用,可以阅读一下 sstardisp.c, 我直接搬运ssd20x 开发板源码的 JpegPlayer
4、这个LVGL7.10 的lv_demo_music 被我改了些参数,下拉窗大小和原装的demo程序不一样。 我就不改回去了反正就是改着玩的。
5、注意修改双缓的缓冲区大小
要修改 /config/fbdev.ini 修改缓冲区到2倍的大小 4800x1024 (原来是4096, 不改会段错误)
FB_BUFFER_LEN = 4800
好了编译跑一下飞起来吧。
视频是跑printer demo 的效果
以下由 @哇酷小管家 从楼主百度网盘下载
------------------------------------
本站下载: LVGL7.10-linux_framebuffer-SSD202-TEVET-PACK-20210223.tar.7z (约65M)
不行哈,我这边搞了一波SSD202 ,测试了下,是要修改 /config/fbdev.ini 修改缓冲区到2倍的大小 4800x1024,然后重启一下。
详见 https://whycan.com/t_6006.html 第14、15楼
另外附上 SSD20X 跑LVGL 的 fbdev相关文件 和 Makefile
LVGL7.10-SSD20X-TEVET_MODIFY.zip
搭车请教一个问题,如果平台(SSD201)的framebuffer打印出来的len是4196304,而按一帧1024@600计算应该是2457600,两倍的关系应该是4915200,目前打印的finfo.smem_len比4915200,在这个情况下还能使用双缓冲吗? 谢谢
嗯,下载编译烧录修改追踪改了一波,
这个打印出来还不够2倍的buffer大小,要修改 /config/fbdev.ini 修改缓冲区到2倍的大小 4800x1024
代码贴一下:
[FB_DEVICE]
FB_HWLAYER_ID = 1
FB_HWWIN_ID = 0
FB_HWLAYER_DST = 3
FB_HWWIN_FORMAT = 5
FB_HWLAYER_OUTPUTCOLOR = 1
FB_WIDTH = 1024
FB_HEIGHT = 600
FB_TIMMING_WIDTH = 1920
FB_TIMMING_HEIGHT = 1080
FB_MMAP_NAME = E_MMAP_ID_FB
FB_BUFFER_LEN = 4800
#unit:Kbyte,4096=4M, fbdev.ko alloc size = FB_BUFFER_LEN*1024
FB_BUFFER_LEN = 4800
这里原来是4096, 修改成4800即可。
显然 1024*600*4 *2 =4915200 ,但是4096*1024 = 4194304 不够用,那就会crash
这里你已经可以成功单缓冲显示了,sstar_disp_init 想必你已经成功调用,这里就不贴了,我贴另一个帖子上。
哥,就是按照大神的帖子改的,ssd201平台finfo.smem_len打印出来不是2倍的buffer,无法切换,会crash, 使用单缓存可以显示,但是页面切换有撕裂感
试一下哈,ligpng可以用其他的png库替代,有就行,LVGL也有版本支持了png , lodepng
链接在这里:
https://github.com/lvgl/lv_lib_png
楼主厉害!正需要呢!!楼主威武!!!
下载下来的linux_frame_buffer 跑在V3S tina
跑起来没有支持png解码,图片啥的程序从单片机那边过来,都是bin啊啥的,ARGB8888 数据超大还占磁盘,很难受啊。
tina环境已经支持了libpng,这里边默认是调用了libpng里边的接口。
话不多说,上代码:
/**
* @file lv_img_decoder.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_img_decoder.h"
#include "../lv_core/lv_debug.h"
#include "../lv_draw/lv_draw_img.h"
#include "../lv_misc/lv_ll.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_gc.h"
#if defined(LV_GC_INCLUDE)
#include LV_GC_INCLUDE
#endif /* LV_ENABLE_GC */
/*********************
* DEFINES
*********************/
#define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
#define CF_BUILT_IN_LAST LV_IMG_CF_ALPHA_8BIT
#define USE_PNG 1
/**********************
* TYPEDEFS
**********************/
typedef struct
{
#if LV_USE_FILESYSTEM
lv_fs_file_t * f;
#endif
lv_color_t * palette;
lv_opa_t * opa;
} lv_img_decoder_built_in_data_t;
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
lv_coord_t len, uint8_t * buf);
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
lv_coord_t len, uint8_t * buf);
static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
lv_coord_t len, uint8_t * buf);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the image decoder module
* */
void lv_img_decoder_init(void)
{
lv_ll_init(&LV_GC_ROOT(_lv_img_defoder_ll), sizeof(lv_img_decoder_t));
lv_img_decoder_t * decoder;
/*Create a decoder for the built in color format*/
decoder = lv_img_decoder_create();
if(decoder == NULL) {
LV_LOG_WARN("lv_img_decoder_init: out of memory");
LV_ASSERT_MEM(decoder);
return;
}
lv_img_decoder_set_info_cb(decoder, lv_img_decoder_built_in_info);
lv_img_decoder_set_open_cb(decoder, lv_img_decoder_built_in_open);
lv_img_decoder_set_read_line_cb(decoder, lv_img_decoder_built_in_read_line);
lv_img_decoder_set_close_cb(decoder, lv_img_decoder_built_in_close);
}
/**
* Get information about an image.
* Try the created image decoder one by one. Once one is able to get info that info will be used.
* @param src the image source. E.g. file name or variable.
* @param header the image info will be stored here
* @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image
*/
lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header)
{
header->always_zero = 0;
lv_res_t res = LV_RES_INV;
lv_img_decoder_t * d;
LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d)
{
res = LV_RES_INV;
if(d->info_cb) {
res = d->info_cb(d, src, header);
if(res == LV_RES_OK) break;
}
}
return res;
}
/**
* Open an image.
* Try the created image decoder one by one. Once one is able to open the image that decoder is save in `dsc`
* @param dsc describe a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable.
* @param src the image source. Can be
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`)
* 2) Variable: Pointer to an `lv_img_dsc_t` variable
* 3) Symbol: E.g. `LV_SYMBOL_OK`
* @param style the style of the image
* @return LV_RES_OK: opened the image. `dsc->img_data` and `dsc->header` are set.
* LV_RES_INV: none of the registered image decoders were able to open the image.
*/
lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style)
{
dsc->style = style;
dsc->src_type = lv_img_src_get_type(src);
dsc->user_data = NULL;
if(dsc->src_type == LV_IMG_SRC_FILE) {
size_t fnlen = strlen(src);
dsc->src = lv_mem_alloc(fnlen + 1);
strcpy((char *)dsc->src, src);
} else {
dsc->src = src;
}
lv_res_t res = LV_RES_INV;
lv_img_decoder_t * d;
LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d)
{
/*Info an Open callbacks are required*/
if(d->info_cb == NULL || d->open_cb == NULL) continue;
res = d->info_cb(d, src, &dsc->header);
if(res != LV_RES_OK) continue;
dsc->error_msg = NULL;
dsc->img_data = NULL;
dsc->decoder = d;
res = d->open_cb(d, dsc);
/*Opened successfully. It is a good decoder to for this image source*/
if(res == LV_RES_OK) break;
}
return res;
}
/**
* Read a line from an opened image
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
* @param x start X coordinate (from left)
* @param y start Y coordinate (from top)
* @param len number of pixels to read
* @param buf store the data here
* @return LV_RES_OK: success; LV_RES_INV: an error occurred
*/
lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
lv_res_t res = LV_RES_INV;
if(dsc->decoder->read_line_cb) res = dsc->decoder->read_line_cb(dsc->decoder, dsc, x, y, len, buf);
return res;
}
/**
* Close a decoding session
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
*/
void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc)
{
if(dsc->decoder) {
if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
if(dsc->src_type == LV_IMG_SRC_FILE) {
lv_mem_free(dsc->src);
dsc->src = NULL;
}
}
}
/**
* Create a new image decoder
* @return pointer to the new image decoder
*/
lv_img_decoder_t * lv_img_decoder_create(void)
{
lv_img_decoder_t * decoder;
decoder = lv_ll_ins_head(&LV_GC_ROOT(_lv_img_defoder_ll));
LV_ASSERT_MEM(decoder);
if(decoder == NULL) return NULL;
memset(decoder, 0, sizeof(lv_img_decoder_t));
return decoder;
}
/**
* Delete an image decoder
* @param decoder pointer to an image decoder
*/
void lv_img_decoder_delete(lv_img_decoder_t * decoder)
{
lv_ll_rem(&LV_GC_ROOT(_lv_img_defoder_ll), decoder);
lv_mem_free(decoder);
}
/**
* Set a callback to get information about the image
* @param decoder pointer to an image decoder
* @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct)
*/
void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb)
{
decoder->info_cb = info_cb;
}
/**
* Set a callback to open an image
* @param decoder pointer to an image decoder
* @param open_cb a function to open an image
*/
void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb)
{
decoder->open_cb = open_cb;
}
/**
* Set a callback to a decoded line of an image
* @param decoder pointer to an image decoder
* @param read_line_cb a function to read a line of an image
*/
void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb)
{
decoder->read_line_cb = read_line_cb;
}
/**
* Set a callback to close a decoding session. E.g. close files and free other resources.
* @param decoder pointer to an image decoder
* @param close_cb a function to close a decoding session
*/
void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb)
{
decoder->close_cb = close_cb;
}
/**
* Get info about a built-in image
* @param decoder the decoder where this function belongs
* @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol
* @param header store the image data here
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
*/
lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
{
(void)decoder; /*Unused*/
lv_img_src_t src_type = lv_img_src_get_type(src);
if(src_type == LV_IMG_SRC_VARIABLE) {
lv_img_cf_t cf = ((lv_img_dsc_t *)src)->header.cf;
if(cf < CF_BUILT_IN_FIRST || cf > CF_BUILT_IN_LAST) return LV_RES_INV;
header->w = ((lv_img_dsc_t *)src)->header.w;
header->h = ((lv_img_dsc_t *)src)->header.h;
header->cf = ((lv_img_dsc_t *)src)->header.cf;
}
#if LV_USE_FILESYSTEM
else if(src_type == LV_IMG_SRC_FILE) {
lv_fs_file_t file;
lv_fs_res_t res;
uint32_t rn;
unsigned short readx = 0,ready = 0;
#if USE_PNG
if(fh_png_getsize(src,&readx,&ready) == 0)//libpng的接口
{
header->w = readx;
header->h = ready;
header->cf = LV_IMG_CF_RAW_ALPHA;
}
#else
res = lv_fs_open(&file, src, LV_FS_MODE_RD);
if(res == LV_FS_RES_OK) {
res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);
//very very important, here copy header , but this file now is png, not bin, so header should modify in pcfs_read
lv_fs_close(&file);
}
if(header->cf < CF_BUILT_IN_FIRST || header->cf > CF_BUILT_IN_LAST) return LV_RES_INV;
#endif
}
#endif
else if(src_type == LV_IMG_SRC_SYMBOL) {
/*The size depend on the font but it is unknown here. It should be handled outside of the
* function*/
header->w = 1;
header->h = 1;
/* Symbols always have transparent parts. Important because of cover check in the design
* function. The actual value doesn't matter because lv_draw_label will draw it*/
header->cf = LV_IMG_CF_ALPHA_1BIT;
} else {
LV_LOG_WARN("Image get info found unknown src type");
return LV_RES_INV;
}
return LV_RES_OK;
}
/**
* Open a built in image
* @param decoder the decoder where this function belongs
* @param dsc pointer to decoder descriptor. `src`, `style` are already initialized in it.
* @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
*/
lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
/*Open the file if it's a file*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
#if LV_USE_FILESYSTEM
#if USE_PNG
/*Support only "*.bin" files*/
if(strcmp(lv_fs_get_ext(dsc->src), "png")) return LV_RES_INV;
// lv_fs_file_t f;
// lv_fs_res_t res = lv_fs_open(&f, dsc->src, LV_FS_MODE_RD);
// if(res != LV_FS_RES_OK) {
// LV_LOG_WARN("Built-in image decoder can't open the file");
// return LV_RES_INV;
// }
/*If the file was open successfully save the file descriptor*/
// if(dsc->user_data == NULL) {
// dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
// if(dsc->user_data == NULL) {
// LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
// LV_ASSERT_MEM(dsc->user_data);
// }
// memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
// }
// lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
// user_data->f = lv_mem_alloc(sizeof(f));
// if(user_data->f == NULL) {
// LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
// LV_ASSERT_MEM(user_data->f);
// }
// memcpy(user_data->f, &f, sizeof(f));
#else
/*Support only "*.bin" files*/
if(strcmp(lv_fs_get_ext(dsc->src), "bin")) return LV_RES_INV;
lv_fs_file_t f;
lv_fs_res_t res = lv_fs_open(&f, dsc->src, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder can't open the file");
return LV_RES_INV;
}
/*If the file was open successfully save the file descriptor*/
if(dsc->user_data == NULL) {
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
if(dsc->user_data == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
LV_ASSERT_MEM(dsc->user_data);
}
memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
}
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
user_data->f = lv_mem_alloc(sizeof(f));
if(user_data->f == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
LV_ASSERT_MEM(user_data->f);
}
memcpy(user_data->f, &f, sizeof(f));
#endif
#else
LV_LOG_WARN("Image built-in decoder cannot read file because LV_USE_FILESYSTEM = 0");
return LV_RES_INV;
#endif
}
lv_img_cf_t cf = dsc->header.cf;
/*Process true color formats*/
if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA || cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
/* In case of uncompressed formats the image stored in the ROM/RAM.
* So simply give its pointer*/
dsc->img_data = ((lv_img_dsc_t *)dsc->src)->data;
return LV_RES_OK;
} else {
/*If it's a file it need to be read line by line later*/
dsc->img_data = NULL;
return LV_RES_OK;
}
}
/*Process indexed images. Build a palette*/
else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || cf == LV_IMG_CF_INDEXED_4BIT ||
cf == LV_IMG_CF_INDEXED_8BIT) {
#if LV_IMG_CF_INDEXED
uint8_t px_size = lv_img_color_format_get_px_size(cf);
uint32_t palette_size = 1 << px_size;
/*Allocate the palette*/
if(dsc->user_data == NULL) {
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
if(dsc->user_data == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
LV_ASSERT_MEM(dsc->user_data);
}
memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
}
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t));
user_data->opa = lv_mem_alloc(palette_size * sizeof(lv_opa_t));
if(user_data->palette == NULL || user_data->opa == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
LV_ASSERT_MEM(user_data->palette);
LV_ASSERT_MEM(user_data->opa);
}
if(dsc->src_type == LV_IMG_SRC_FILE) {
/*Read the palette from file*/
#if LV_USE_FILESYSTEM
lv_fs_seek(user_data->f, 4); /*Skip the header*/
lv_color32_t cur_color;
uint32_t i;
for(i = 0; i < palette_size; i++) {
lv_fs_read(user_data->f, &cur_color, sizeof(lv_color32_t), NULL);
user_data->palette[i] = lv_color_make(cur_color.ch.red, cur_color.ch.green, cur_color.ch.blue);
user_data->opa[i] = cur_color.ch.alpha;
}
#else
LV_LOG_WARN("Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0");
return LV_RES_INV;
#endif
} else {
/*The palette begins in the beginning of the image data. Just point to it.*/
lv_color32_t * palette_p = (lv_color32_t *)((lv_img_dsc_t *)dsc->src)->data;
uint32_t i;
for(i = 0; i < palette_size; i++) {
user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
user_data->opa[i] = palette_p[i].ch.alpha;
}
}
dsc->img_data = NULL;
return LV_RES_OK;
#else
LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED");
return LV_RES_INV;
#endif
}
/*Alpha indexed images. */
else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || cf == LV_IMG_CF_ALPHA_4BIT ||
cf == LV_IMG_CF_ALPHA_8BIT) {
#if LV_IMG_CF_ALPHA
dsc->img_data = NULL;
return LV_RES_OK; /*Nothing to process*/
#else
LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA");
return LV_RES_INV;
#endif
}
#if USE_PNG
else if(cf == LV_IMG_CF_RAW_ALPHA)
{
// uint8_t *pbuf;
int file_size;
file_size = (dsc->header.w)*(dsc->header.h)*(LV_COLOR_DEPTH/8);
dsc->img_data = lv_mem_alloc(file_size);
fh_png_load(dsc->src,dsc->img_data,dsc->header.w,dsc->header.h);//libpng的接口
printf("lv_img_decoder_built_in_open fh_png_load src = %s file_size = %d \n",dsc->src,file_size);
return LV_RES_OK;
}
#endif
/*Unknown format. Can't decode it.*/
else {
/*Free the potentially allocated memories*/
lv_img_decoder_built_in_close(decoder, dsc);
LV_LOG_WARN("Image decoder open: unknown color format")
return LV_RES_INV;
}
}
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
* Required only if the "open" function can't return with the whole decoded pixel array.
* @param decoder pointer to the decoder the function associated with
* @param dsc pointer to decoder descriptor
* @param x start x coordinate
* @param y start y coordinate
* @param len number of pixels to decode
* @param buf a buffer to store the decoded pixels
* @return LV_RES_OK: ok; LV_RES_INV: failed
*/
lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
(void)decoder; /*Unused*/
lv_res_t res = LV_RES_INV;
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
/* For TRUE_COLOR images read line required only for files.
* For variables the image data was returned in `open`*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
res = lv_img_decoder_built_in_line_true_color(dsc, x, y, len, buf);
}
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
res = lv_img_decoder_built_in_line_alpha(dsc, x, y, len, buf);
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
res = lv_img_decoder_built_in_line_indexed(dsc, x, y, len, buf);
} else {
LV_LOG_WARN("Built-in image decoder read not supports the color format");
return LV_RES_INV;
}
return res;
}
/**
* Close the pending decoding. Free resources etc.
* @param decoder pointer to the decoder the function associated with
* @param dsc pointer to decoder descriptor
*/
void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
(void)decoder; /*Unused*/
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
#if USE_PNG
if(dsc->img_data)
{
lv_mem_free(dsc->img_data);
}
#endif
if(user_data) {
#if LV_USE_FILESYSTEM
if(user_data->f) {
lv_fs_close(user_data->f);
lv_mem_free(user_data->f);
}
#endif
if(user_data->palette) lv_mem_free(user_data->palette);
if(user_data->opa) lv_mem_free(user_data->opa);
lv_mem_free(user_data);
dsc->user_data = NULL;
}
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
lv_coord_t len, uint8_t * buf)
{
#if LV_USE_FILESYSTEM
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
lv_fs_res_t res;
uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf);
uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3;
pos += 4; /*Skip the header*/
res = lv_fs_seek(user_data->f, pos);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder seek failed");
return LV_RES_INV;
}
uint32_t btr = len * (px_size >> 3);
uint32_t br = 0;
lv_fs_read(user_data->f, buf, btr, &br);
if(res != LV_FS_RES_OK || btr != br) {
LV_LOG_WARN("Built-in image decoder read failed");
return LV_RES_INV;
}
return LV_RES_OK;
#else
LV_LOG_WARN("Image built-in decoder cannot read file because LV_USE_FILESYSTEM = 0");
return LV_RES_INV;
#endif
}
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
lv_coord_t len, uint8_t * buf)
{
#if LV_IMG_CF_ALPHA
const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255};
/*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
lv_color_t bg_color = dsc->style->image.color;
lv_coord_t i;
for(i = 0; i < len; i++) {
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
#elif LV_COLOR_DEPTH == 16
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
#elif LV_COLOR_DEPTH == 32
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
#else
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
#endif
}
const lv_opa_t * opa_table = NULL;
uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
uint32_t ofs = 0;
int8_t pos = 0;
switch(dsc->header.cf) {
case LV_IMG_CF_ALPHA_1BIT:
w = (dsc->header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(dsc->header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
pos = 7 - (x & 0x7);
opa_table = alpha1_opa_table;
break;
case LV_IMG_CF_ALPHA_2BIT:
w = (dsc->header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(dsc->header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
pos = 6 - ((x & 0x3) * 2);
opa_table = alpha2_opa_table;
break;
case LV_IMG_CF_ALPHA_4BIT:
w = (dsc->header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(dsc->header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
pos = 4 - ((x & 0x1) * 4);
opa_table = alpha4_opa_table;
break;
case LV_IMG_CF_ALPHA_8BIT:
w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
pos = 0;
break;
}
#if LV_USE_FILESYSTEM
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
uint8_t fs_buf[LV_HOR_RES_MAX];
#endif
const uint8_t * data_tmp = NULL;
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = dsc->src;
data_tmp = img_dsc->data + ofs;
} else {
#if LV_USE_FILESYSTEM
lv_fs_seek(user_data->f, ofs + 4); /*+4 to skip the header*/
lv_fs_read(user_data->f, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN("Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
for(i = 0; i < len; i++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
dsc->header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN("Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}
static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
lv_coord_t len, uint8_t * buf)
{
#if LV_IMG_CF_INDEXED
uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
int8_t pos = 0;
uint32_t ofs = 0;
switch(dsc->header.cf) {
case LV_IMG_CF_INDEXED_1BIT:
w = (dsc->header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(dsc->header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
ofs += 8; /*Skip the palette*/
pos = 7 - (x & 0x7);
break;
case LV_IMG_CF_INDEXED_2BIT:
w = (dsc->header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(dsc->header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
ofs += 16; /*Skip the palette*/
pos = 6 - ((x & 0x3) * 2);
break;
case LV_IMG_CF_INDEXED_4BIT:
w = (dsc->header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(dsc->header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
ofs += 64; /*Skip the palette*/
pos = 4 - ((x & 0x1) * 4);
break;
case LV_IMG_CF_INDEXED_8BIT:
w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
ofs += 1024; /*Skip the palette*/
pos = 0;
break;
}
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
#if LV_USE_FILESYSTEM
uint8_t fs_buf[LV_HOR_RES_MAX];
#endif
const uint8_t * data_tmp = NULL;
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = dsc->src;
data_tmp = img_dsc->data + ofs;
} else {
#if LV_USE_FILESYSTEM
lv_fs_seek(user_data->f, ofs + 4); /*+4 to skip the header*/
lv_fs_read(user_data->f, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN("Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t val_act;
lv_coord_t i;
for(i = 0; i < len; i++) {
val_act = (*data_tmp & (mask << pos)) >> pos;
lv_color_t color = user_data->palette[val_act];
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full;
#elif LV_COLOR_DEPTH == 16
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full & 0xFF;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (color.full >> 8) & 0xFF;
#elif LV_COLOR_DEPTH == 32
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = color.full;
#else
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
#endif
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = user_data->opa[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN("Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}
注意看一下宏定义USE_PNG 下添加的代码,其实添加的东西很少。
主要3个处理:
1、返回图像的大小和类型
2、读取PNG的元数据(直接解出来后的)
3、关闭解码器的时候释放掉解出来的时候申请的内存
当前这个操作的情况下,可以直接在初始化的时候加入图片列表png文件:
形如:
lv_img_dsc_t *image;
image->header.cf = LV_IMG_CF_RAW_ALPHA;
image->header.always_zero = 0;
image->data = file_name;//file_name 就是png文件路径
能调用Png解码到内存显示后,可以调整:
lv_conf.h的
# define LV_MEM_SIZE (2U * 1024U * 1024U)
可以限制LVGL使用的内存大小,然后和cache配合使用,在下面:
lv_conf.h的
#define LV_IMG_CACHE_DEF_SIZE 5
可以约束调用解码显示到当前页面的缓冲图片源数量,减少访问图片源文件次数
完结,撒花~
下载下来的linux_frame_buffer 跑在V3S tina
跑起来没有支持双缓,画面切换撕裂很难受呀,
可以支持FBIOPAN_DISPLAY的平台应该都可以相同的操作。
话不多说,上代码:
/**
* @file fbdev.c
*
*/
/*********************
* INCLUDES
*********************/
#include "fbdev.h"
#if USE_FBDEV || USE_BSD_FBDEV
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#if USE_BSD_FBDEV
#include <sys/fcntl.h>
#include <sys/time.h>
#include <sys/consio.h>
#include <sys/fbio.h>
#else /* USE_BSD_FBDEV */
#include <linux/fb.h>
#include <pthread.h>
#include <sys/epoll.h>
#endif /* USE_BSD_FBDEV */
/*********************
* DEFINES
*********************/
#ifndef FBDEV_PATH
#define FBDEV_PATH "/dev/fb0"
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STRUCTURES
**********************/
struct bsd_fb_var_info{
uint32_t xoffset;
uint32_t yoffset;
uint32_t xres;
uint32_t yres;
int bits_per_pixel;
};
struct bsd_fb_fix_info{
long int line_length;
long int smem_len;
};
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
#if USE_BSD_FBDEV
static struct bsd_fb_var_info vinfo;
static struct bsd_fb_fix_info finfo;
#else
static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;
#endif /* USE_BSD_FBDEV */
static char *fbp = 0,*fbpbase = 0;
static long int screensize = 0;
static long int half_screensize = 0;
static int fbfd = 0;
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void fbdev_init(void)
{
// Open the file for reading and writing
fbfd = open(FBDEV_PATH, O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
return;
}
printf("The framebuffer device was opened successfully.\n");
#if USE_BSD_FBDEV
struct fbtype fb;
unsigned line_length;
//Get fb type
if (ioctl(fbfd, FBIOGTYPE, &fb) != 0) {
perror("ioctl(FBIOGTYPE)");
return;
}
//Get screen width
if (ioctl(fbfd, FBIO_GETLINEWIDTH, &line_length) != 0) {
perror("ioctl(FBIO_GETLINEWIDTH)");
return;
}
vinfo.xres = (unsigned) fb.fb_width;
vinfo.yres = (unsigned) fb.fb_height;
vinfo.bits_per_pixel = fb.fb_depth + 8;
vinfo.xoffset = 0;
vinfo.yoffset = 0;
finfo.line_length = line_length;
finfo.smem_len = finfo.line_length * vinfo.yres;
#else /* USE_BSD_FBDEV */
// Get fixed screen information
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
return;
}
// Get variable screen information
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
return;
}
#endif /* USE_BSD_FBDEV */
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
// Figure out the size of the screen in bytes
screensize = finfo.smem_len; //finfo.line_length * vinfo.yres;
half_screensize = screensize/2;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
fbpbase = fbp;
if((intptr_t)fbp == -1) {
perror("Error: failed to map framebuffer device to memory");
return;
}
memset(fbp, 0, screensize);
printf("The framebuffer device was mapped to memory successfully.\n");
}
void fbdev_exit(void)
{
close(fbfd);
}
char toggle = 0;
/**
* Flush a buffer to the marked area
* @param drv pointer to driver where this function belongs
* @param area an area where to copy `color_p`
* @param color_p an array of pixel to copy to the `area` part of the screen
*/
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
if(fbp == NULL ||
area->x2 < 0 ||
area->y2 < 0 ||
area->x1 > (int32_t)vinfo.xres - 1 ||
area->y1 > (int32_t)vinfo.yres - 1) {
lv_disp_flush_ready(drv);
return;
}
if(toggle == 0)
{
toggle = 1;
vinfo.yoffset = 0;
fbp =fbpbase;
}
else
{
toggle = 0;
vinfo.yoffset = vinfo.yres;
fbp = fbpbase + half_screensize;
}
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2;
int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2;
lv_coord_t w = (act_x2 - act_x1 + 1);
long int location = 0;
long int byte_location = 0;
unsigned char bit_location = 0;
/*32 or 24 bit per pixel*/
if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) {
uint32_t * fbp32 = (uint32_t *)fbp;
int32_t y;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 ) + (y ) * finfo.line_length / 4;
memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4);
color_p += w;
}
}
else {
/*Not supported bit per pixel*/
}
// memcpy(fbp,tmpbuf,640*480*4);
if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
fprintf(stderr, "active fb swap failed\n");
}
//May be some direct update command is required
//ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));
lv_disp_flush_ready(drv);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif
其实就是标准的linux下的ioctl双缓操作,
另外,这个操作要在初始化lvgl的时候加入双缓冲区。
static lv_color_t buf[DISP_BUF_SIZE],buf1[DISP_BUF_SIZE];
static lv_disp_buf_t disp_buf;
lv_disp_buf_init(&disp_buf, buf, buf1, DISP_BUF_SIZE);
这里的 DISP_BUF_SIZE 要和显存大小一致,我这里用了ARGB 8888。
编译操作一下,画面撕裂消失,起飞!
分享全志主线u-boot/linux 打包 TF/SD/SDNAND 镜像脚本
http://whycan.com/t_4008.html
(出处:哇酷开发者社区【全志 V3S/F1C100s/X3】)
谢谢分享,
如题,感觉拿个TF卡刷入镜像再dd出来有点愚蠢。所以……
根据CSDN的帖子:
https://blog.csdn.net/armkits/article/details/93848472
我用的是256MB 的sd nand
自己摸索了一下下,汇总在下面:
qemu-img create V3S-OK.img 245M
sfdisk --in-order --Linux --unit M ./V3S-OK.img <<EOF
4,20,L
,,L
EOF
kpartx -av V3S-OK.img
mkfs.vfat -F 16 /dev/mapper/loop0p1 -n boot
mkfs.ext4 /dev/mapper/loop0p2 -L rootfs
dd if=../Lichee/u-boot/u-boot-sunxi-with-spl.bin of=./V3S-OK.img bs=1024 seek=8 conv=notrunc
mount /dev/mapper/loop0p1 tmpmnt/boot/ &&\
mount /dev/mapper/loop0p2 tmpmnt/rootfs/ &&\
cd tmpmnt/boot/ && \
cp ../../../Lichee/linux/arch/arm/boot/zImage . && \
cp ../../../Lichee/linux/arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dtb . && \
cp ../../../zero_imager/boot.scr .
cd ../rootfs/
tar -xvf ../../../Lichee/buildroot/backuptotalokrootfs_20200922/rootfs.tar -C .
cd ../.. && \
umount ./tmpmnt/boot/ && \
umount ./tmpmnt/rootfs/ && \
kpartx -dv V3S-OK.img
大致描述一下:
1、生成一个245MB的空固件Img
qemu-img create V3S-OK.img 245M
2、分个区, 4,20,L 代表第一个分区是20M, 4代表20M前面空4MB空间出来, L是个ID,传送门:
http://manpages.ubuntu.com/manpages//trusty/en/man8/sfdisk.8.html
Id is given in hex, without the 0x prefix, or is [E|S|L|X], where L (LINUX_NATIVE (83)) is
the default, S is LINUX_SWAP (82), E is EXTENDED_PARTITION (5), and X is LINUX_EXTENDED
(85).
sfdisk --in-order --Linux --unit M ./V3S-OK.img <<EOF
4,20,L
,,L
EOF
kpartx 把分区挂载到文件系统 , 会在 /dev/mapper/ 下面生成节点loopXpx
kpartx -av V3S-OK.img
格式化一下,按照荔枝派zero的教程,第一个分区是fat16 ,第二个是ext4
mkfs.vfat -F 16 /dev/mapper/loop0p1 -n boot
mkfs.ext4 /dev/mapper/loop0p2 -L rootfs
写入uboot :
dd if=../Lichee/u-boot/u-boot-sunxi-with-spl.bin of=./V3S-OK.img bs=1024 seek=8 conv=notrunc
挂载并拷贝内核和rootfs:
mount /dev/mapper/loop0p1 tmpmnt/boot/ &&\
mount /dev/mapper/loop0p2 tmpmnt/rootfs/ &&\
cd tmpmnt/boot/ && \
cp ../../../Lichee/linux/arch/arm/boot/zImage . && \
cp ../../../Lichee/linux/arch/arm/boot/dts/sun8i-v3s-licheepi-zero-dock.dtb . && \
cp ../../../zero_imager/boot.scr .
cd ../rootfs/
tar -xvf ../../../Lichee/buildroot/backuptotalokrootfs_20200922/rootfs.tar -C .
cd ../.. && \
umount ./tmpmnt/boot/ && \
umount ./tmpmnt/rootfs/ && \
最后解除文件系统挂载:
kpartx -dv V3S-OK.img
然后就可以用win32diskImage 刷入了,起飞!
控制手机的上一首下一首也搞定了,
了解了一下dbus-send
可以用来发送上一首下一首
播放:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_C4_86_E9_B9_E3_4C org.bluez.MediaControl1.Play
暂停:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_C4_86_E9_B9_E3_4C org.bluez.MediaControl1.Pause
下一曲:
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_C4_86_E9_B9_E3_4C org.bluez.MediaControl1.Next
上一曲
dbus-send --system --print-reply --dest=org.bluez /org/bluez/hci0/dev_C4_86_E9_B9_E3_4C org.bluez.MediaControl1.Previous
更多功能细节还在学习和挖掘。
现在有2个地方有点蛋疼,
1、设置蓝牙手机端音量,上一首,下一首,停止,播放 这个的实现应该是要用AVRTP来做,但是似乎这个东西挑安卓和苹果,安卓死活没有看到相关音量的log。
至于操作现在还在摸索。
2、声音听起来有些歌曲会有点偶发的沙沙叫,网抑云的安静的SQ的曲子更容易听出来,不知道是我手机问题还是这个模块要修改驱动? 感觉是丢帧了求大佬交流起来!
沙沙响的问题,我编译了vlc进文件系统,搞了一波,直接扔flac文件,vlc 播放原来的在手机上的flac 文件,也是有问题的,这个响声像是codec输出的耳机信号有问题! 我接了个小功放,把高频拉低,就很难听到,看来可能是CODEC的输出的问题,研究一下硬件和寄存器先!
晕哥有没试过rtl8723bs,3Mbps速率的情况
上传一下portaudio播放的代码,解压到/port/posix-h5/目录下,直接make就行
需要安装portaudio
不会是我连接的杜邦线太长了吧(捂脸.jpg)
test.rar
看到配置文件了,
/lib/firmware/rtl_bt/rtlbt_config
这个东西是可以自己随意改的么?
# cat /lib/firmware/rtl_bt/rtlbt_config | hexdump
0000000 ab55 8723 0031 00f4 0108 0000 0500 0050
0000010 0c00 1000 8002 0492 c550 19ea 1be1 aff1
0000020 015f 0ba4 0027 6301 00fe 0101 015b 0b04
0000030 0b0b e30a 0101 0000
0000037
看到了 0000010 0c00 1000 8002 0492 c550 19ea 1be1 aff1
其中的04928002 我可以自己改? 想设置高一点,一点点排除问题。
晕哥有没试过rtl8723bs,3Mbps速率的情况
上传一下portaudio播放的代码,解压到/port/posix-h5/目录下,直接make就行
需要安装portaudio
不会是我连接的杜邦线太长了吧(捂脸.jpg)
test.rar
大佬,如何设置3M的通信波特率? 修改rtl8723bs_bt的驱动代码么,我看波特率设置数值是从芯片那边读过来的。
Realtek Bluetooth :config baud rate to :4928002, hwflowcontrol:5f, 1
对应的:
{0x04928002, 1500000},
咋改成 3000000 呢? 我这边是这样,高码率流的曲子, 会出现偶发的沙沙响,正在想办法查。
如题,这个好像比较少人lu顺过?
我也是小白,一上来啥也不知道, 用buildroot2017的版本出来的pulse直接启动不了,也不管那么多了,直接干上buildroot2020.02.6
传个配置文件在附件如下
buildroot-2020_02_6_config.zip
其他的按照荔枝派的文档搞:
https://licheezero.readthedocs.io/zh/latest/%E8%B4%A1%E7%8C%AE/article%205.html?highlight=bt#id2
好,文件系统搞上。
启动,
start_bt.sh ttyS2
pulseaudio -D
/usr/libexec/bluetooth/bluetoothd &
hciconfig hci0 up
hciconfig hci0 class 0x200420
bluetoothctl
pairable on
discoverable on
然后用手机连上,bluetoothctl 可能会提示:[NEW] Device C4:86:E9:B9:E3:4C HUAWEI Mate 9
Request confirmation
[agent] Confirm passkey 075360 (yes/no):
输入yes
后续会提示授权service
Authorize service
[agent] Authorize service 00001108-0000-1000-8000-00805f9b34fb (yes/no):
输入yes
Authorize service
[agent] Authorize service 0000110d-0000-1000-8000-00805f9b34fb (yes/no):
输入yes
然后手机播歌,记得开声卡的播放静音。
amixer -c 0 sset 'Headphone',0 50% unmute
插上耳机,起飞!
如题,这玩意儿很多人都lu过成功了。
老规矩上过程:
1、clone
https://github.com/lvgl/lv_port_linux_frame_buffer.git
2、改Makefile
#CC ?= gcc
CC := arm-linux-gnueabihf-gcc
3、make
4、加触摸
荔枝派zero 已经有电阻屏了,直接用 evdev,校准也搞一下,diff一波:
diff --git a/lv_drv_conf.h b/lv_drv_conf.h
index 975c7b4..3623d2d 100644
--- a/lv_drv_conf.h
+++ b/lv_drv_conf.h
@@ -314,18 +314,18 @@
#endif
/*-------------------------------------------------
* Mouse or touchpad as evdev interface (for Linux based systems)
*------------------------------------------------*/
#ifndef USE_EVDEV
-# define USE_EVDEV 0
+# define USE_EVDEV 1
#endif
#if USE_EVDEV
-# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
+# define EVDEV_NAME "/dev/input/event1" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/
# define EVDEV_SCALE 0 /* Scale input, e.g. if touchscreen resolution does not match display resolution */
@@ -334,11 +334,11 @@
# define EVDEV_SCALE_VER_RES (4096) /* Vertical resolution of touchscreen */
# endif /*EVDEV_SCALE*/
-# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
+# define EVDEV_CALIBRATE 1 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
# if EVDEV_CALIBRATE
-# define EVDEV_HOR_MIN 3800 /*If EVDEV_XXX_MIN > EVDEV_XXX_MAX the XXX axis is automatically inverted*/
-# define EVDEV_HOR_MAX 200
-# define EVDEV_VER_MIN 200
+# define EVDEV_HOR_MIN 200 /*If EVDEV_XXX_MIN > EVDEV_XXX_MAX the XXX axis is automatically inverted*/
+# define EVDEV_HOR_MAX 3800
+# define EVDEV_VER_MIN 400
# define EVDEV_VER_MAX 3800
# endif /*EVDEV_SCALE*/
#endif /*USE_EVDEV*/
别忘了初始化加入触摸设备注册一下回调函数:
diff --git a/main.c b/main.c
index d286cc7..317a604 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,8 @@
#include "lvgl/lvgl.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_examples/lv_examples.h"
+#include "lv_drivers/indev/evdev.h"
+#include "lvgl/src/lv_hal/lv_hal_indev.h"
#include <unistd.h>
#include <pthread.h>
#include <time.h>
@@ -30,6 +32,14 @@ int main(void)
disp_drv.flush_cb = fbdev_flush;
lv_disp_drv_register(&disp_drv);
+
+ lv_indev_drv_t indev_drv;
+ lv_indev_drv_init(&indev_drv); /*Basic initialization*/
+ evdev_init();
+ indev_drv.type = LV_INDEV_TYPE_POINTER; /*See below.*/
+ indev_drv.read_cb = evdev_read; /*See below.*/
+ lv_indev_drv_register(&indev_drv); /*Register the driver in LittlevGL*/
+
/*Create a Demo*/
lv_demo_widgets();
再编译一下。
起飞!
加图片我还不是很熟悉,lvgl7.0 懂的都懂。
页次: 1