我没用openocd,找到了个minilink软件也能debug,不过有些bug,单步不太好用。
https://github.com/cnlohr/ch32v003fun
这个项目不错,有minilink的使用方法。
https://github.com/cnlohr/rv003usb
汇编实现了usb协议栈
gosunxifel.zip
关于闪退问题,将exe文件替换成这个,应该就可以了
下面的连接脚本,有很多段不是很明白,有大佬能解释一下吗?比如.fini_array ,.ctors, .dtors
ENTRY( jump_reset )
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 2K
}
SECTIONS
{
.init :
{
_sinit = .;
. = ALIGN(4);
KEEP(*(SORT_NONE(.init.jump)))
KEEP(*(SORT_NONE(.init.vectors)))
. = ALIGN(4);
_einit = .;
} >FLASH AT>FLASH
.text :
{
. = ALIGN(4);
*(.text)
*(.text.*)
*(.rodata)
*(.rodata*)
*(.gnu.linkonce.t.*)
. = ALIGN(4);
} >FLASH AT>FLASH
.fini :
{
KEEP(*(SORT_NONE(.fini)))
. = ALIGN(4);
} >FLASH AT>FLASH
PROVIDE( _etext = . );
PROVIDE( _eitcm = . );
.preinit_array :
{
PROVIDE_HIDDEN(__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN(__preinit_array_end = .);
} >FLASH AT>FLASH
.init_array :
{
PROVIDE_HIDDEN(__init_array_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP(*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN(__init_array_end = .);
} >FLASH AT>FLASH
.fini_array :
{
PROVIDE_HIDDEN(__fini_array_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP(*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN(__fini_array_end = .);
} >FLASH AT>FLASH
.ctors :
{
KEEP(*crtbegin.o(.ctors))
KEEP(*crtbegin?.o(.ctors))
KEEP(*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP(*(SORT(.ctors.*)))
KEEP(*(.ctors))
} >FLASH AT>FLASH
.dtors :
{
KEEP(*crtbegin.o(.dtors))
KEEP(*crtbegin?.o(.dtors))
KEEP(*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP(*(SORT(.dtors.*)))
KEEP(*(.dtors))
} >FLASH AT>FLASH
.dalign :
{
. = ALIGN(4);
PROVIDE(_data_vma = .);
} >RAM AT>FLASH
.dlalign :
{
. = ALIGN(4);
PROVIDE(_data_lma = .);
} >FLASH AT>FLASH
.data :
{
. = ALIGN(4);
*(.gnu.linkonce.r.*)
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.sdata2*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
. = ALIGN(4);
PROVIDE( _edata = .);
} >RAM AT>FLASH
.bss :
{
. = ALIGN(4);
PROVIDE( _sbss = .);
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss*)
*(.gnu.linkonce.b.*)
*(COMMON*)
. = ALIGN(4);
PROVIDE( _ebss = .);
} >RAM AT>FLASH
PROVIDE( _end = _ebss);
PROVIDE( end = . );
PROVIDE( _eusrstack = ORIGIN(RAM) + LENGTH(RAM));
}
首先介绍一下背景:以下是plan9的故事
例一、替换 CPU
假想一下我们有一台日常使用但性能不佳的笔记本,和一台不在本地但性能强劲的服务器。 我们当然能够使用远程计算机的强劲的 CPU 运行一些计算量特大的程序。这不是什么难事,因为几乎所有操作系统都支持登陆到远程的机器。然而,麻烦的是,如果在远程运行程序需要读写本地的文件,或者访问挂载在本地笔记本上的打印机,扬声器麦克风之类设备,我们除了在本地和远程之间把文件传来传去之外,并没有什么好方法。特别的,如果我们想借用另一台计算机上强劲的 CPU 做音频和视频解码,来播放一个放在本机光盘驱动器里的电影文件的话,我们是不可能指望远程计算机既能读本地的光驱,又能把音频投递到本机的扬声器上的。
Plan 9 中,有一个简单的 cpu 命令,能够让用户自然地使用一个其他机器上的 CPU 运行程序,且仍然能够访问本地的所有文件和设备。也就是说,我们可以用远程计算机上强劲的 CPU 做图像处理,媒体解码等任务,并且可以直接把声音播放到本地的扬声器。cpu 命令给人的感觉,是除了给机器换个了 cpu 外,其他一切都和原来一样。这个看似 “神奇” 的功能,其实在 Plan 9 里实现起来一点都不复杂: cpu 指令首先连接服务器上,然后将本地的所有资源和文件系统,包括窗口管理器,光盘驱动器,扬声器等设备(别忘了他们都是文件),一股脑儿挂载到服务器上,成为服务器上的资源。这样,在服务器上运行的程序,就可以“自然地”使用本地的键盘鼠标和显示器完成交互,还可以访问你本地的显示器扬声器等设备。
cpu 命令真的就是名副其实的换掉了本地计算机的 cpu (其实还有内存)而保留其他一切设备。Plan 9 的这个 cpu 命令,带有强烈的分布式操作系统的特征,而我们平时接触的操作系统都不是分布式操作系统,因此 cpu 这个命令至今在现代主流操作系统上没有完全等价物。
现在这个牛逼的cpu命令移植到了linux系统,它是完全用go实现的。
请看以下简介:
The u-root cpu command
Do you want to have all the tools on your linuxboot system that you have on your desktop, but you can’t get them to fit in your tiny flash part? Do you want all your desktop files visible on your linuxboot system, but just remembered there’s no disk on your linuxboot system? Are you tired of using scp or wget to move files around? Do you want to run emacs or vim on the linuxboot machine, but know they can’t ever fit? What about zsh? How about being able to run commands on your linuxboot machine and have the output appear on your home file system? You say you’d like to make this all work without having to fill out web forms in triplicate to get your organization to Do Magic to your desktop?
Your search is over: cpu is here to answer all your usability needs.
The problem: running your program on some other system
People often need to run a command on a remote system. That is easy when the remote system is the same as the system you are on, e.g., both systems are Ubuntu 16.04; and all the libraries, packages, and files are roughly the same. But what if the systems are different, say, Ubuntu 16.04 and Ubuntu 18.10? What if one is Centos, the other Debian? What if a required package is missing on the remote system, even though in all other ways they are the same?
While these systems are both Linux, and hence can provide Application Binary Interface (ABI) stability at the system call boundary, above that boundary stability vanishes. Even small variations between Ubuntu versions matter: symbol versions in C libraries differ, files are moved, and so on.
What is a user to do if they want to build a binary on one system, and run it on another system?
The simplest approach is to copy the source to that other system and compile it. That works sometimes. But there are limits: copying the source might not be allowed; the code might not even compile on the remote system; some support code might not be available, as for a library; and for embedded systems, there might not be a compiler on the remote system. Copy and compile is not always an option. In fact it rarely works nowadays, when even different Linux distributions are incompatible.
The next option is to use static linking. Static linking is the oldest form of binary on Linux systems. While it has the downside of creating larger binaries, in an age of efficient compilers that remove dead code, 100 gigabit networks, and giant disks and memory, that penalty is not the problem it once was. The growth in size of static binaries is nothing like the growth in efficiency and scale of our resources. Nevertheless, static linking is frowned upon nowadays and many libraries are only made available for dynamic linking.
Our user might use one of the many tools that package a binary and all its libraries into a single file, to be executed elsewhere. The u-root project even offers one such tool, called pox, for portable executables. Pox uses the dynamic loader to figure out all the shared libraries a program uses, and place them into the archive as well. Further, the user can specify additional files to carry along in case they are needed.
The problem here is that, if our user cares about binary size, this option is even worse. Deadcode removal won’t work; the whole shared library has to be carried along. Nevertheless, this can work, in some cases.
So our user packages up their executable using pox or a similar tool, uses scp to get it to the remote machine, logs in via ssh, and all seems to be well, until at some point there is another message about a missing shared library! How can this be? The program that packaged it up checked for all possible shared libraries.
Unfortunately, shared libraries are now in the habit of loading other shared libraries, as determined by reading text files. It’s no longer possible to know what shared libraries are used; they can even change from one run of the program to the next. One can not find them all just by reading the shared library itself. A good example is the name service switch library, which uses /etc/nsswitch.conf to find other shared libraries. If nsswitch.conf is missing, or a library is missing, some versions of the name service switch library will core dump.
Not only must our user remember to bring along /etc/nsswitch.conf, they must also remember to bring along all the libraries it might use. This is also true of other services such as Pluggable Authentication Modules (PAM). And, further, the program they bring along might run other programs, with their own dependencies. At some point, as the set of files grows, frustrated users might decide to gather up all of /etc/, /bin, and other directories, in the hope that a wide enough net might bring along all that’s needed. The remote system will need lots of spare disk or memory! We’re right back where we started, with too many files for too little space.
In the worst case, to properly run a binary from one system, on another system, one must copy everything in the local file system to the remote system. That is obviously difficult, and might be impossible if the remote system has no disk, only memory.
One might propose having the remote system mount the local system via NFS or Samba. While this was a common approach years ago, it comes with its own set of problems: all the remote systems are now hostage to the reliability of the NFS or Samba server. But there’s a bigger problem: there is still no guarantee that the remote system is using the same library versions and files that the user’s desktop is using. The NFS server might provide, e.g., Suse, to the remote system; the user’s desktop might be running Ubuntu. If the user compiles on their desktop, the binary might still not run on the remote system, as the Suse libraries might be different. This is a common problem.
Still worse, with an NFS root, everyone can see everyone’s files. It’s like living in an apartment building with glass walls. Glass houses only look good in architecture magazines. People want privacy.
https://github.com/u-root/cpu
https://book.linuxboot.org/cpu/
keil的也换成LLVM了,https://www2.keil.com/mdk5/compiler/6/
看到一份官网开发文档https://doc.zh-jieli.com/AC79/zh-cn/master/index.html,然后在淘宝和b站都有看到官方在普及芯片。芯片性价比真是无敌呀
@echo
关于py32f003的isp烧录,我在网上找到了个方法,还没实际操作过不知道行不行。主要是这句话:上电1s内默认是isp编程模式。
https://blog.csdn.net/firseve/article/details/126661827
BL808_RM_zhBL808_RM_zh.pdf
BL808_DS_zhBL808_DS_zh.pdf
这价格如果在10元左右,f1c100s可以退休了
https://www.cnx-software.com/2022/10/10/pine64-ox64-sbc-bl808-risc-v-multi-protocol-wisoc-64mb-ram/
SoC – Bouffalo Lab BL808 with:
CPU
Alibaba T-head C906 64-bit RISC-V core @ 480MHz
Alibaba T-head E907 32-bit RISC-V core @ 320MHz
Memory – 64MB embedded DRAM
AI accelerator – NPU BLAI-100 (Bouffalo Lab AI engine) for video/audio detection/recognition
Wireless
2.4 GHz 802.11 b/g/n Wi-Fi 4
Bluetooth 5.x dual mode (classic + BLE)
IEEE 802.15.4 for Zigbee
Display
Up to 4-lane MIPI DSI
Up to 8-bit MIPI DBI
16-bit MIPI DPI
QSPI
Audio Codec – 2x ADC, 1x DAC, sample rate: 8 to 192KHz, 24-bit
Camera
2-lane MIPI CSI and DVP interfaces
MJPEG and H.264 encoder up to 1920×1080 @ 30fps + 640×480 @ 30fps
Package – 88-pin QFN
Storage
16Mbit (2MB) or 128Mbit (16MB) XSPI NOR flash
MicroSD socket with support for SDHC and SDXC
Camera & audio – 2-lane MIPI CSI co-located with USB-C port for camera module including microphone and speaker
Antenna – 2.4GHz chip antenna soldered on board, footprint for u.FL connector
USB – 1x USB 2.0 OTG Type-C port with MIPI CSI “alternative” mode
Expansion – 2x 20-pin headers with castellated holes with GPIO, SPI, I2C, and UART, possible I2S and GMII expansion
Debugging – 5-pin JTAG header
Misc – BOOT button, red power LED
Power Supply – 5V/0.5A via USB Type-C port or micro USB port
Dimensions – 51 x 21 x 19mm
跟着https://blog.csdn.net/qq_41253675/article/details/124898690操作,在tiny200s上把系统跑起来了
@Jeason1997
https://whycan.com/t_4149.html
有个地方不太理解:
__image_file_start = .;
.text : AT(__image_file_start) //就是这里,表示代码链接到DDR内,但编译时存放在文
这里有几个地址没有想明白,依我看启动过程是:brom程序从spi flash拷贝固定大小(不记得是多大了)的二进制文件到sram中,cpu开始从sram的0地址执行指令,指令中有个拷贝代码的程序如下:
/* 加载程序 */
void Boot_Load_Code(void)
{
Boot_SPI0_Init();
Boot_SPI_Flash_Read((unsigned int)&__image_file_start, &__image_start, &__image_end - &__image_start);
Boot_SPI0_Exit();
}
__image_file_start是spi flash的存放位置,二进制程序被拷贝到ddr的地址起始位置,然后cpu跳转到ddr开始执行。
我所不理解的是__image_file_start如果是二进制文件在spi flash的存储位置,那__image_start应该是ddr的开始位置
.text : AT(__image_file_start)
{
PROVIDE(__image_start = .);
Obj/start.o (.text)
Obj/main.o (.text)
*(.text)
*(.note.gnu.build-id)
} > ddr
那__image_start的地址具体是多少呢?为何不把二进制程序拷贝到ddr的起始位置呢?由于对链接脚本不太熟,决定做实验验证:先直接修改链接脚本,把__image_start 的地址直接修改成0x80000000
go语言裸机最小生成elf工程:
add_20220409-1201.zip
另外还可以参考https://git.sr.ht/~eliasnaur/unik/tree,eggos作者就是受这个项目启发做的。两者原理是一样的
@xboot
同感,tinygo等于发明了另一种语言,还是跟随官方go比较好。TamaGo就是增加GOARCH GOOS的方案。但是我更倾向eggos的方案,不用修改官方编译器,他是模拟了linux的中断和系统调用。具体原理请参考这篇博文:https://zhuanlan.zhihu.com/p/265806072
go和c现在是我工作中的主力语言。go在很多领域发挥了强大作用,那go适合嵌入式吗?当前并不适合,但go具有控制硬件的能力,虽然有些繁琐。
本帖最终目的是在全志f1c100s/200s或者说是arm9系列芯片直接运行go程序,主要是把go runtime移植到arm9上。本帖主要是受github的开源项目https://github.com/icexin/eggos的启发,此项目已成功将go runtime移植到x86上。开篇先建立环境:
虚拟环境是qemu-system-arm
先在上面跑个gnu汇编热热身。
arm.zip
当前应用的开发模式逐渐都在web化,无论是从桌面端到移动端,都从本地app转向web开发。具体地说,之前桌面端开发模式主要有delphi、qt、vs等,现在正在向electron、nodejs、渐进式Web 应用(PWA)转移。移动端从android和ios本地应用,逐渐被小程序和轻应用替代。这种种迹象已经表明web正在吞噬一切。而最近几年有一个关键技术备受关注,那就是WebAssembly。web应用的一个最大问题是运行速度,WebAssembly的引入使得web应用速度得到很大提升。而且可以支持多种语言编程编译成WebAssembly。
从sipeed买了d1的哪咤计算条,看到介绍waft。深入了解发现waft非常有前途,可能是未来iot设备应用的开发形态。ui开发的一个痛点就是定制化,想要灵活多变很耗时间。而web模式的开发就是多变,可以轻松实现定制化需求。最近今年各种小程序层出不穷,但都是基于android或ios的大厂app之上构建。但这种情况正在逐渐发生变化,微信有了小程序硬件框架,阿里有了waft。把小程序的依赖环境从app分离,直接把依赖安装到其他系统或硬件之上,使得小程序可以适用的范围不断扩大。相信不久小程序如果哪一天跑在了串口屏上也不要太过惊讶,这只是未来iot应用开发模式的初级阶段。我们经历了功能机走向智能机,同样在5G技术和万物互联的影响下,又一次技术革命拉开了序幕。
看到一篇不错的分析riscv代码密度的文章:
https://developer.aliyun.com/article/783932
v2指令集和riscv的详细差异:
https://www.bilibili.com/video/av89605854/
@echo
左侧导航栏有大量的芯片公司在用(有连接具体芯片型号可跳过去查看),视觉处理dsp,hifi音频解码dsp,ai等都是基于Xtensa架构。
没错,dsp用的指令集也是xtensa,这是官网说明:
Every Tensilica DSP and processor includes the same base Xtensa ISA that delivers modern, high-performance RISC processor benefits. Shipping at a rate of over 4 billion cores per year, Cadence’s Tensilica processor and DSP portfolio is the number 2 volume 32-bit processor in the market.
维基百科看到,微软Hololens的协处理器就是用的Tensilica dsp做的。从这些例子可以看到xtensa架构很适合做dsp等复杂密集型数字信号处理应用
比如?哪个厂的什么产品?
kekemuyu 说:其他厂家并不像乐鑫一样开放,所以我们不了解。国外很多大厂在用
官网: https://www.cadence.com/en_US/home/tools/ip/tensilica-ip/partners.html#siliconservices
nrf蓝牙芯片有个很有意思的外设ppi,可编程外设互联。进一步了解得知nrf系列的外设的寄存器很不一样,nRF52832 的寄存器分为下面的三种类型。
Task :任务寄存器,可以由程序或事件触发。
Event:事件寄存器,事件可以产生中断或触发任务。
Register:普通寄存器,和一般单片机的寄存器一样。
Task 和 event 使得操作片上外设十分方便简洁,只需进行少量的配置,即可轻松运用各种外设。同时,Task 和 event 能有效减少 CPU 的占用时间,降低 CPU 的负荷。
Task 和 Event 更多的是用来和 PPI(可编程外设互连)配合使用,通过 PPI 将某个 Event和 Task 连接起来,连接后,该 Event 即可触发对应的 Task 执行相应的功能。
不知道其他蓝牙芯外设是否有同样设计,这是第一次发现这样有趣的设计,应该是为低功耗而生的设计。最近发现很多mcu芯片开始集成一些fpga类似的功能,比如rp2040的可编程io,这次的ppi也有异曲同工之妙。估计以后的芯片设计方向都会加入类此的外设。
@491990741
不好意思,驱动不太懂。我只是按照https://github.com/micropython/micropython/tree/master/ports/esp32编译后生成的固件就直接支持psram了。
make BOARD=UM_TINYPICO
@491990741
我也不太了解,电路参考了tinypico的https://www.tinypico.com/tinypico-nano。具体代码实现,我知道的是在micropython里有针对tinypico的设置,你可以看一下。
ble点灯程序功耗实测,官方的例程中有四个led和四个按键,需要把不需要的按键注释掉,只保留一个led,如下:
int main(void)
{
// Initialize.
log_init();
NRF_LOG_INFO("Blinky example started.");
leds_init();
timers_init();
//buttons_init();
power_management_init();
ble_stack_init();
gap_params_init();
gatt_init();
services_init();
advertising_init();
conn_params_init();
// Start execution.
NRF_LOG_INFO("Blinky example started.");
advertising_start();
// Enter main loop.
for (;;)
{
idle_state_handle();
}
}
sdk_config.h中开启dcdc使能,由于模块没有外接32k晶振,使能内部rc(内部rc要比外部晶振功耗增加几个ua)。
重点优化功耗的几个参数:
广播间隔越大, 功耗越低;
广播持续时间越长,功耗越大
蓝牙BLE设备联结后,蓝牙主机会向BLE设备发送连接事件(Connection Events),BLE设备接收到连接事件后,会进行回复,以通知蓝牙主机连接通路正常。而这是BLE设备连接后最耗电的工况,所以增加连接间隔时间会降低BLE设备的功耗,但是需要注意的是,改变连接间隔时间就相应地会改变蓝牙的通讯速度。
从机延时(Slave Latency)次数,就是在连接时忽略连接事件的次数。
#define APP_ADV_INTERVAL 640 /**< The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms). */
#define APP_ADV_DURATION BLE_GAP_ADV_TIMEOUT_LIMITED_MAX//BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising time-out (in units of seconds). When set to 0, we will never time out. */
#define MIN_CONN_INTERVAL MSEC_TO_UNITS(1000, UNIT_1_25_MS) /**< Minimum acceptable connection interval (0.5 seconds). */
#define MAX_CONN_INTERVAL MSEC_TO_UNITS(2000, UNIT_1_25_MS) /**< Maximum acceptable connection interval (1 second). */
#define SLAVE_LATENCY 0 /**< Slave latency. */
#define CONN_SUP_TIMEOUT MSEC_TO_UNITS(6000, UNIT_10_MS) /**< Connection supervisory time-out (4 seconds). */
这些参数需要综合考虑,因为参数之间是有关联的,设置不当反而会适得其反,以上设置的参数可能并不是最优的甚至是错误的,需要学习这些参数的具体原理。以下是官方给出的功耗优化建议:
https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/optimizing-power-on-nrf52-designs
由于测试条件有限,万用表并不适合测量这么低功耗的射频芯片。功率分析仪可能会好些,大概用万用表测了一下,广播电流在15ua左右(有跳动但是太快测不出,官方有个理论评估在线工具:
https://devzone.nordicsemi.com/nordic/power/w/opp/2/online-power-profiler-for-ble
简单评估了一下广播功耗大概23ua:
功耗测试,看到nrf52811的手册功耗参数有点吓人,1mhz运行功耗是34.4 µA,经过实测基本符合手册,官方的点灯程序修改一下测得是2.69ma,然后除以64mhz,平均功耗是42ua,可能需要优化才能达到官方数据吧,不管了,42ua的运行功耗也是很优秀了。
#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "boards.h"
/**
* @brief Function for application main entry.
*/
int main(void)
{
/* Configure board. */
//bsp_board_init(BSP_INIT_LEDS);
/* Toggle LEDs. */
while (true)
{
// for (int i = 0; i < LEDS_NUMBER; i++)
// {
// bsp_board_led_invert(i);
// nrf_delay_ms(500);
// }
}
}
作为全球蓝牙份额占比最大的nordic公司,其nrf52系列非常经典,广泛用于物联网、可穿戴设备。而且其协议栈紧跟蓝牙标准,怀疑nordic中有人参与标准的制定。开发环境非常亲民,keil、gcc、ses(SEGGER公司开发)等,开贴记录一下填一下坑。
1.keil环境下,直接用pack installer把对应的包在线安装即可
2.从nrf官方下载sdk
3.点灯
4.ble点灯
官方sdk中有examples,其中大多数例子是基于nrf52840或nrf52832的。由于我买的是nrf52811模块,所以例子需要做一些修改。
例子中的pca10056是nrf52840,pca10056e对应的是nrf52811(是官方从pca10056复制并修改了一些配置)。
点灯程序很顺利,按照自己的板子修改一下io即可。
ble点灯就不是很顺利了,遇到的问题是日志无法打印,无法发现蓝牙设备,开始以为是协议栈烧录有问题,反复折腾还是不行。后来拆开模块屏蔽罩发现没有32.768k的晶振,而协议栈工作是需要低速时钟的,由于官方例子默认是外部晶振,所以修改配置后解决问题。至此,蓝牙可以完美工作。
内部rc修改步骤:
其中source是时钟源,rc_ctiv是校准定时器间隔,rc_temp_ctiv是恒温下的软装置校准计时器间隔,accuracy是外部时钟的精度。
与四个结构体成员相关的宏定义在sdk_config.h文件下,修改相关的宏就可以设置低频时钟的来源。
1).source的宏:NRF_SDH_CLOCK_LF_SRC,置0选择NRF_CLOCK_LF_SRC_RC----内部RC振荡,置1选择NRF_CLOCK_LF_SRC_XTAL ----外部晶振。
2).rc_ctiv的宏:NRF_SDH_CLOCK_LF_RC_CTIV,选择内部RC时值为16,选择外部晶体时值为0.
3).rc_temp_ctiv:NRF_SDH_CLOCK_LF_RC_TEMP_CTIV,选择内部RC时值为2,选择外部晶体时值为0.
4).accuracy:NRF_SDH_CLOCK_LF_ACCURACY,内部RC时置选择NRF_CLOCK_LF_ACCURACY_500_PPM,选择外部晶体时根据实际参考精度设置。
ble点灯视频:
kekemuyu 说:同样是WROVER-B,cpu ram init到99.60%的时候,速度突然变慢,而且卡在了下图:
https://whycan.com/files/members/1315/Screenshot121824.png这里是在解压,压缩率有点高,解压有点慢。
感觉有点不正常啊,几个小时了,才解压31%。就像我说的在ram init到99.60%的时候突然变慢,似乎有在此时就不正常了。
移植过程比较简单,不用按照官方文档(有点跟不上代码更新的速度),过程如下:
1.在arduino的ide中下载三个库:lvgl和lvgl_examples,驱动库TFT_eSPI
2.修改TFT_eSPI的User_Setup_Select.h文件,使能对应的驱动芯片
修改TFT_eSPI\User_Setups的驱动文件,修改对应管脚。
3.复制lvgl中的lv_conf_template.h改名为lv_conf.h并移植到lvgl上层目录,同样复制lvgl_examples中的lv_demo_conf_template.h改名为lv_demo_conf.h并移植到lvgl_examples上层目录
4.修改lv_conf.h和lv_demo_conf.h这两个文件,这个就是使能或禁用某些参数,按需配置即可
5.最后编译arduino对应的demo,可能或报错,说找不到某些文件,应该是lvgl_examples中的某些文件引用的路径不对,修改一下即可。
路径报错需要修改的文件
@qwert1213131
sipeed tb店,实测和手册基本一致
@metro
Gerber_PCB_LineTinyBL702.zip
后面的跟贴内容可能会一直涉及编译原理的内容,有些晦涩,只有对编译原理感兴趣的同学才会感兴趣吧!无论如何编译原理是了解计算机本质的一种途径,它涉及到计算体系的各个方面,学之受益无穷。今天就让编译原理这个大棒降维打击一下表达式的求解。
让程序求解一个表达式如123+234*(12/2),应该如何出处理呢?不同的思路可能有不同的答案,这里用编译原理这把牛刀宰它。
整体思路:
词法分析->语法分析->语义分析
其中需要说明的是语义分析是包含在语法分析中的,因为用的是语法制导翻译方法。
0.文法
E->T E1
E1->op1|T fun1 E1|null
T->F T1
T1->op2 F fun1 T1| null
F->(E)|-F fun2|I
I->const fun3
op1->+fun4|-fun5
op2->*fun6|/fun6
1.词法分析
词法分析是比较简单,主要分为三类:
数字:0-9
界符:( )
运算符:+,-,*,/
建立词法分析表(只是举例和代码并不匹配):
由词法分析表驱动词法解析程序,效果如下:
token结构是:
type Token struct {
Kind int //类型
Content string //值
RowNum int //行数
}
[{1 123 0} {2 + 0} {1 234 0} {2 * 0} {3 ( 0} {1 12 0} {2 / 0} {1 2 0} {3 ) 0}]
2.语法分析
核心框图:
由文法规则获取first集和follow集,进而建立语法分析表:
var sParseTable = [8][8]string{
// + - * / const ( ) $
{"err", "T,E1", "err", "err", "T,E1", "T,E1", "err", "err"}, //E
{"op1,T,fun1,E1", "op1,T,fun1,E1", "err", "err", "err", "err", "null", "null"}, //E1
{"err", "F,T1", "err", "err", "F,T1", "F,T1", "err", "err"}, //T
{"null", "null", "op2,F,fun1,T1", "op2,F,fun1,T1", "err", "err", "null", "null"}, //T1
{"err", "-,F,fun2", "err", "err", "I", "(,E,)", "err", "err"}, //F
{"err", "err", "err", "err", "const,fun3", "err", "err", "err"}, //I
{"+,fun4", "-,fun5", "err", "err", "err", "err", "err", "err"}, //op1
{"err", "err", "*,fun6", "/,fun7", "err", "err", "err", "err"}, //op2
}
分析器核心程序:
func (c *Calc) Parse() bool {
iListPos := 0
var ival DataStack
for c.ParseStack.Len() != 0 && iListPos < len(c.TokenList) {
el := c.ParseStack.Back()
ival = el.Value.(DataStack)
c.ParseStack.Remove(el)
if ival.Kind == "VT" { //非终结符
icol := "$"
if c.TokenList[iListPos].Kind == TOKEN_KIND_CONST {
icol = "const"
} else if c.TokenList[iListPos].Kind == TOKEN_KIND_OPRATOR {
icol = c.TokenList[iListPos].Content
} else if c.TokenList[iListPos].Kind == TOKEN_KIND_SPLITE {
icol = c.TokenList[iListPos].Content
}
if v, ok := c.ParseTables[Pcell{ival.Data, icol}]; ok { //查询语法分析表
if v.Data == "err" {
log.Fatal("row,col:", ival.Data, c.TokenList[iListPos])
} else if v.Data == "null" {
continue
} else {
tmp := strings.Split(v.Data, ",")
for k, _ := range tmp {
re := tmp[len(tmp)-k-1]
kind := ""
if isVT(re) {
kind = "VT" //非终结
} else if isFUN(re) {
kind = "FUN" //语义部分
} else {
kind = "VN" //终结
}
ds := DataStack{
Data: re,
Kind: kind,
}
c.ParseStack.PushBack(ds) //反序入栈
}
}
} else {
log.Fatal("row,col:", ival.Data, c.TokenList[iListPos])
}
} else if ival.Kind == "VN" { //终结符
fmt.Println("VN:", ival)
iListPos += 1 //下一个输入流
} else if ival.Kind == "FUN" { //语义处理
fmt.Println("FUN:", ival)
switch ival.Data {
case "fun1":
c.fun1()
case "fun2":
c.fun2()
case "fun3":
c.fun3(c.TokenList[iListPos-1].Content)
case "fun4":
c.fun4()
case "fun5":
c.fun5()
case "fun6":
c.fun6()
case "fun7":
c.fun7()
}
// fmt.Println("FUN END:", c.OprateDataStack.Back().Value, c.OprateSplitStack.Back().Value)
}
ps := make([]string, 0)
for i := c.ParseStack.Back(); i != nil; i = i.Prev() {
ps = append(ps, i.Value.(DataStack).Data)
}
fmt.Println("ps:", ps)
}
if c.ParseStack.Len() == 0 && iListPos == len(c.TokenList) {
c.Result = c.OprateDataStack.Back().Value.(string)
return true
} else {
return false
}
}
现在代码还有点乱,等整理后会上传至github。有词法分析和语法制导翻译的知识可以基本写一个简单的avr汇编器了。
@司徒
只是引导linux,坛子里有人做过了。代码才3k,https://whycan.com/t_5060.html
atiny13没有硬件串口,用软件模拟。发送模拟比较简单,接收就有点复杂了,先做发送。汇编模拟串口发送:
;
; ***********************************
; * (Add program task here) *
; * (Add AVR type and version here) *
; * (C)2019 by Gerhard Schmidt *
; ***********************************
;
.nolist
.include "tn13adef.inc" ; Define device ATtiny13A
.list
;
; **********************************
; H A R D W A R E
; **********************************
;
; (F2 adds ASCII pin-out for device here)
;
; **********************************
; P O R T S A N D P I N S
; **********************************
;
; (Add symbols for all ports and port pins with ".equ" here)
; (e.g. .equ pDirD = DDRB ; Define a direction port
; or
; .equ bMyPinO = PORTB0 ; Define an output pin)
;
; **********************************
; A D J U S T A B L E C O N S T
; **********************************
;
; (Add all user adjustable constants here, e.g.)
.equ clock=9600000 ; Define the clock frequency
.equ baudRate=115200
.equ TX_DELAY = (clock / baudRate - 9) / 3;
;.equ cycle_t = 1000000 / clock
.equ wait_cnt_10us = 10 ;10 / cycle_t / 10
;
; **********************************
; F I X & D E R I V. C O N S T
; **********************************
;
; (Add symbols for fixed and derived constants here)
;
; **********************************
; R E G I S T E R S
; **********************************
;
; free: R0 to R14
.def rSreg = R15 ; Save/Restore status port
.def rmp = R16 ; Define multipurpose register
; free: R17 to R29
; used: R31:R30 = Z for ...
;
.def TX_BITS_NBR_TMP = R18
.def WAIT_NBR_TMP = R19
.def BYTE_TO_TRANSMIT = R24
.def WAIT_NBR = R22
; **********************************
; S R A M
; **********************************
;
.dseg
.org SRAM_START
; (Add labels for SRAM locations here, e.g.
; sLabel1:
; .byte 16 ; Reserve 16 bytes)
;
; **********************************
; C O D E
; **********************************
;
.cseg
.org 000000
;
; **********************************
; R E S E T & I N T - V E C T O R S
; **********************************
rjmp Main ; Reset vector
reti ; INT0
reti ; PCI0
reti ; OVF0
reti ; ERDY
reti ; ACI
reti ; OC0A
reti ; OC0B
reti ; WDT
reti ; ADCC
;
; **********************************
; I N T - S E R V I C E R O U T .
; **********************************
;
; (Add all interrupt service routines here)
;
; **********************************
; M A I N P R O G R A M I N I T
; **********************************
;
Main:
ldi rmp,Low(RAMEND)
out SPL,rmp ; Init LSB stack pointer
; ...
; sei ; Enable interrupts
;
; **********************************
; P R O G R A M L O O P
; **********************************
;
ldi WAIT_NBR,TX_DELAY
ldi BYTE_TO_TRANSMIT,0x0A
rcall SerialAsmTx_4
Loop:
ldi WAIT_NBR,TX_DELAY
ldi BYTE_TO_TRANSMIT,0x0A
rcall SerialAsmTx_4
ldi r28,50
rcall delay_500ms
rjmp loop
;
; End of source code
SerialAsmTx_4:
cli
sbi DDRB, PB4
ldi TX_BITS_NBR_TMP, 10
com BYTE_TO_TRANSMIT
TxLoop_4:
brcc Tx1_4
cbi PORTB, PB4
Tx1_4:
brcs TxDone_4
sbi PORTB, PB4
TxDone_4:
mov WAIT_NBR_TMP, WAIT_NBR
TxDelay_4:
dec WAIT_NBR_TMP
brne TxDelay_4
lsr BYTE_TO_TRANSMIT
dec TX_BITS_NBR_TMP
brne TxLoop_4
reti
;10 cycles,per loop
delay_500ms:
ldi r25,wait_cnt_10us
ldi r26,100
ldi r27,10
loop1:
nop
nop
nop
nop
nop
nop
nop
dec r25
brne loop1
dec r26
ldi r25, wait_cnt_10us
brne loop1
ldi r26,100
dec r27
brne loop1
ldi r27,10
dec r28
brne loop1
ret
;
; (Add Copyright information here, e.g.
; .db "(C)2019 by Gerhard Schmidt " ; Source code readable
; .db "C(2)10 9ybG reahdrS hcimtd " ; Machine code format
;
如果不介意编程语言,我推荐《编译器设计之路》这本书。这是一本实战的书,里面有pascal编译器的完整实现及源码。代码量不大,很适合入门。
这个编译器的源码是c++实现,源码地址:https://sourceforge.net/projects/neopascal/
从来不以功利目的去学习技术,只是跟随兴趣。学习汇编也是对计算机底层的兴趣,从学编程的第一天开始就对操作系统、编译原理感兴趣。
最近研究汇编也是为了学习写汇编器、编译器。前几天刚把avr的汇编器的词法分析部分写完。写汇编器之前,想参考一下开源的汇编器,发现除了gcc的,很少有人专门写一个汇编器了(除了cpu设计公司,甚至他们也是给gcc写个后端)。有意思的是看到了一个avr的开源汇编器是pascal写的,分析了一下竟然没有按照编译原理写,硬是靠自己的想法堆出来了。它的地址:http://www.avr-asm-tutorial.net/gavrasm/index_en.html,有兴趣可以看一下。
avr单片机是很经典的8位mcu,因为arduino的火爆,直到现在依然很流行。在8位单片机开创性的引入了32个寄存器,两级流水线,risc结构直接降维打击了同时代的8051。以avr为例,探究一下计算机的本质。研究计算机原理可以看书,也可以做试验。我选择从试验开始,这样更有趣一些。现在做实验简单多了,各种虚拟环境和ide非常丰富。我选择用真机做实验,这样更实用和真实一些。
首先介绍一下用到的工具:
1.atmel studio,主要用它编译和仿真汇编代码
2.硬件,一个avr最小系统,我选择attiny13,研究汇编够用了
3.烧写器usb isp,以及烧写工具智峰下载器
4.avr汇编指令集手册,以及attiny13的手册
开篇上点灯程序:
.cseg
.org $0
rjmp start
.org $000A
start:
sbi DDRB,DDB0
sbi PORTB,PB0
Loop:
rjmp loop
机器码对照:
.cseg
.org $0
000000 c009 rjmp start
.org $000A
start:
00000a 9ab8 sbi DDRB,DDB0
00000b 9ac0 sbi PORTB,PB0
Loop:
00000c cfff rjmp loop
hex格式
:020000020000FC
:0200000009C035
:06001400B89AC09AFFCF6C
:00000001FF
flash memery快照:
prog 0x0000 09 c0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff b8 9a c0 9a
prog 0x0018 ff cf ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
hex格式解释:
数据个数 地址 类型 数据 crc校验
: 00 0000 00 000000... 00
下载器使用hex文件烧录数据到avr,中间经过了解析hex文件的过程。主要是取出机器码并烧录到flash。
avr的汇编格式是:
操作码---操作数/地址/空---操作数/地址/空
整条指令是16位或是32位(32位很少)
avr整个工作过程是,从mcu上电开始,pc指向flash的0地址,开始取指-执行重复下去,直至结束。我们每天使用的电脑办公、手机刷视频,在cpu看来都是一堆01010101。
我们可以用汇编开发mcu,也可以直接用机器码开发。上古计算机就是机器码编程,那时候是没有falsh,直接把01代码用纸带打孔的方式来表示,也就是说纸带相当于falsh。即使现在用机器码开发,比那时候也简单多了,直接在电脑上查询寄存器的地址并转为相应的机器码,然后烧进falsh即可。
今天研究了一下avr的汇编指令,发现第一条指令必须要是rjmp或其他跳转(跳转到主程序),否则程序就跑飞了。把主程序放到falsh的$0000000位置也不行。
cpu不是从flash的0位置顺序读取指令执行吗? 为什么第一条必须是跳转才行?
正确代码:
.org 000000
rjmp start
nop
start:
ldi r16,0xFF
out DDRB,r16
sbi PORTB,PB0
Loop:
rjmp loop
错误:
start:
ldi r16,0xFF
out DDRB,r16
sbi PORTB,PB0
Loop:
rjmp loop
今年早些时候,Raspberry Pi基金会宣布推出4美元的Raspberry Pi Pico和RP2040微控制器用于嵌入式开发。现在,RP2040芯片正在通过他们的经销商以仅1美元的价格出售,供那些想用这种树莓派芯片构建自己的电子产品的人使用。
1美元的RP2040芯片包含两个133MHz的ARM Cortex-M0+内核,可以运行FreeRTOS和MicroPython等软件。除了这两个嵌入式内核外,还自带264KB的内存和对这种类型的控制器的所有常见I/O接口的支持。
树莓派基金会宣布,他们今年已经运送了超过60万块Raspberry Pi Pico单板,还有另外70万块的订单等待交付。同时,更多的创作者和其他企业一直在寻求使用RP2040芯片建立自己的产品,这让他们现在可以以低至1美元的单件销售价格提供该芯片。
预计到今年秋天RP2040芯片将 "大量上市"。关于RP2040供应的更多细节请查阅RaspberryPi.org。
首先在线仿真地址:http://tice.sea.eseo.fr/riscv/,选择这个主要是因为比较好玩直观。
这个模拟器是支持gnu的编译器的,所以先安装编译器:
sudo apt install gcc-riscv64-unknown-elf
模拟器gpio寄存器:
点灯程序:
/*
* Configure the GPIO with:
* - Byte 0: 8 LEDs
* - Byte 1: 8 toggle switches
*/
.text
.global __reset
__reset:
j start
start:
li x1, 0xd0000000
/* Set first GPIO byte as outputs */
sb x0, (x1)
li x3, 0xff
sb x3, 0x10(x1)
j .
.section gpio_config, "a"
leds: .byte 3, 3, 3, 3, 3, 3, 3, 3
sws: .byte 2, 2, 2, 2, 2, 2, 2, 2
编译文件:
riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -c -o led.o led.s
连接成elf文件:
riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -T rv32e.ld -o led.elf led.o
连接文件rv32e.ld
ENTRY(__reset)
MEM_SIZE = 4K;
STACK_SIZE = 512;
BITMAP_SIZE = 1K;
SECTIONS {
. = 0x0;
.text : {
*(vectors)
*(.text)
__text_end = .;
}
.data : { *(.data) }
.rodata : { *(.rodata) }
__global_pointer = ALIGN(4);
.bss ALIGN(4) : {
__bss_start = .;
*(.bss COMMON)
__bss_end = ALIGN(4);
}
. = MEM_SIZE - STACK_SIZE - BITMAP_SIZE;
.stack ALIGN(4) : {
__stack_start = .;
. += STACK_SIZE;
__stack_pointer = .;
}
.bitmap ALIGN(4) : {
__bitmap_start = .;
*(bitmap)
}
__bitmap_end = __bitmap_start + BITMAP_SIZE;
}
生成intel格式hex:
riscv64-unknown-elf-objcopy -O ihex led.elf led.hex
最后附上在线仿真器的文档说明:http://tice.sea.eseo.fr/riscv/doc/
芯片被打磨掉了,不知道哪位大神知道型号。问题是电脑突然不识别设备了,显示未知设备。可能是有一次调试芯片时正负接反了导致。st
stm32f103c8t6的stlink固件:
ST-Link固件V2.J16.S4.hex.7z
开源吗
开源,刚创建了个仓库:
https://github.com/vineio/vine
现在正在开发阶段,核心功能已完成。主要功能网口和多串口透传数据。
架构组成:
1.vined模块(运行在开发板),可任意扩展
2.vinelookup模块(可运行在开发板或pc),模块注册和发现
3.vineadmin模块(运行在pc),可视化管理,数据展示
硬件构成:任意可运行linux并且带串口和网口的板子
软件:go语言开发,跨平台
路线图和支持特性如下:
1.分布式,可任意平行扩展,模块化管理
2.数据监控,过滤,持久化
3.支持以http,tcp,udp等协议向指定串口透传数据
4.。。。。
测试效果如下,在win10虚拟4个串口,打开两个串口工具分别打开com2和com4,分别向vined模块发送数据,vined建立通串口和网络的透传通道,就可以获取串口数据:
kekemuyu 说:声明式ui,还是流行的web前端比较合适(html,css,js三剑客)。sciter就是基于这种技术实现,体积也比较小,不过需要linux(gtk)。
https://whycan.com/files/members/1315/Screenshot211109.pngsciter不是完整实现,React和VUE都跑不起来的。
不过作为一个HTML引擎,sciter确实很小巧才几个MB。我也关注很久了,学生时代就关注过,那时候它还很简陋,现在强大多了
前端web不用框架开发桌面级程序也是很简单的.
主要用到了esp32-ble-gamepad库:https://github.com/lemmingDev/ESP32-BLE-Gamepad/releases
视频链接:
https://www.zhihu.com/zvideo/1375148539052380160
bellard的riscv&x86模拟器
https://bellard.org/tinyemu/
打开任何一个天气网站的首页,它会自动定位你的本地ip地址,并显示出你所在位置的天气信息。根据这个特性,我们可以从它的首页抓取天气信息。
import urequests
import ure
url="https://www.qweather.com/"
html=urequests.get(url)
text=html.text.replace(" ","")
text_length=len(text)
regex=ure.compile("condition__tmp.*<")
obj=None
index=0
while obj is None:
if index>=text_length:
break
obj=regex.search(text[index:index+1000])
index=index+1000
print(index)
print(obj.group(0))
好漂亮,什么软件画的图?
用的 https://www.processon.com/ ,是个在线工具
复刻国外odroidgo开源掌机,原理图和源码都是开源的,我修改了电源部分和制作了新的外壳。esp32处理器,240mhz主频双核,16M的falsh,8m的psram,wifi,蓝牙。16g的tf卡。有需要者请联系wildgeek_mumu。
通过slip(串行互联网协议)实现的,这里是wiki详细介绍:
https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol
相对于spi或者sdio接口方式,串口的配置更加简单。已经通过笔记本验证,下次验证f1c100s。
https://github.com/martin-ger/esp_slip_router
Usage as STA
In this mode the ESP connects to the internet via an AP with ssid, password and offers at UART0 a SLIP interface with IP address 192.168.240.1. This default can be changed in the file user_config.h.
To connect a Linux-based host, start the firmware on the ESP, connect it via serial to USB, and use the following commands on the host:
sudo slattach -L -p slip -s 115200 /dev/ttyUSB0&
sudo ifconfig sl0 192.168.240.2 pointopoint 192.168.240.1 up mtu 1500
now
telnet 192.168.240.1 7777
gives you terminal access to the esp as router. On the ESP you then enter:
CMD>set ssid <your_ssid>
CMD>set password <your_pw>
CMD>set use_ap 0
CMD>save
CMD>reset
To get full internet access you will need aditionally a route:
sudo route add default gw 192.168.240.1
and a DNS server - add an appropriate entry (e.g. public DNS server) in /etc/resolv.conf, eg. by (as root):
echo "nameserver 9.9.9.9" > /etc/resolv.conf
把line-watch功能拆分,做成了开发板。
开发板特点:
1.核心模块+扩展模块模式,灵活配置,释放你的想象力
2.依托于micropython平台和自建的iotbbs物联网应用市场(正在建设中),实现设备端下载安装应用的功能,更新颖的设备端软件开发方式
3.核心板已集成bm8563实时时钟,锂电池供电,oled1306屏幕,4个功能按键,10个io扩展口,一个l红色led。esp32芯片可以wifi和蓝牙。
4.硬件、软件以及涉及到的手机端工具软件完全开源。
全志科技今日宣布推出「D1」处理器,其是全球首颗量产的搭载平头哥玄铁 906 RISC-V 的应用处理器,为万物互联 AIoT 时代提供了新的智能关键芯片。
https://weibo.com/ttarticle/p/show?id=2310474626222876328399
linewatch是生态建设的引子。未来会有更多硬件加入生态建设中,以micropython为中心,建立起一系列的物联网硬件设备。软件生态正在不短完善中,可能会出现越来越多的iot应用,也可能有小游戏的产品加入,还会有什么样的物联网产品加入谁知道呢?
西瓜视频详细讲解:
https://www.ixigua.com/6949787996174582285?logTag=c4d5450ed3ea8e7edd11
软件名称:aidlearning
是国人开发,网址:http://www.aidlearning.net/
移动端AI开发第一平台
天生强大,Aid在Android上构架了一个支持图形化界面的完整Linux系统
几乎支持所有深度学习开发框架:caffe/mxnet/keras/torch/tensorflow/ncnn/opencv...
内置了强大的编程IDE和开发工具
在pc端可以访问手机端的aidlearning系统,效果如下:
kekemuyu 说:qllbee 说:我说错了 这个是横版的,确实一直更新, 竖版的需要刷机或者改机再刷 司徒的是竖版的老版本
我这不还没刷吗 需要先备份然后先折腾折腾原版系统....然而编程器不给力...
我的这个是最早版本的 得改机那种所有版本都有的https://github.com/TriForceX/MiyooCFW
https://whycan.com/files/members/1315/2021-02-02145308.png我可以很明确的告诉你,这个开源工程有很多问题,你烧录一下自己编译的就知道了,当然你直接下载他的镜像烧录是OK的,而且我跟作者联系过,我基本断定它并不是真的开源.掌机谈开源就是个笑话,想玩还是自己撸比猜别人的更简单.
是吗?这倒是没注意,是不是版本不对,他wiki里写的“Note: The source codes availables are only for Bittboy v3 or less. For Bittboy v3.5 or PocketGo the source code is not confirmed that will work yet.”
开源的游戏系统也不能说完全没有,RetroPie应该是完全开源的。
我说错了 这个是横版的,确实一直更新, 竖版的需要刷机或者改机再刷 司徒的是竖版的老版本
我这不还没刷吗 需要先备份然后先折腾折腾原版系统....然而编程器不给力...
我的这个是最早版本的 得改机那种
kekemuyu 说:读spifalsh做什么? linux内核和文件系统都在tf卡里
有的是不在tf卡里....全在spi里面....
如果是为了获取最新的miyoo源码,这里有最新的,而且还在持续更新https://whycan.com/t_2998.html
amazing! pio is like the third CPU. That can excute assemble instruntions. Although ,it only has 9 instruntions.
理论上来说只要是cpu都可以运行linux或unix,只要ram和falsh够大,原理是在单片机(无论是8bit,16bit,32bit,即使不带mmu)上模拟可以运行linux的cpu。
https://www-cnx--software-com.cdn.amppr … p32-soc%2F
The relatively popular Digital Equipment Corporation (DEC) PDP-11 16-bit minicomputers started selling in the 70s, and were still available in the earlier 90s. While being stuck in Europe due to COVID-19 restrictions, Jeroen Domburg (aka Sprite_tm) decided to design a tiny replica of a DEC VT102 PDP-11 terminal based on ESP32 wireless SoC and running 2.11 BSD UNIX through SimH PDP11 emulator.
https://www.raspberrypi.org/documentation/pico/getting-started/
Board Specifications
Raspberry Pi Pico is a low-cost, high-performance microcontroller board with flexible digital interfaces. Key features include:
RP2040 microcontroller chip designed by Raspberry Pi in the United Kingdom
Dual-core Arm Cortex M0+ processor, flexible clock running up to 133 MHz
264KB of SRAM, and 2MB of on-board Flash memory
Castellated module allows soldering direct to carrier boards
USB 1.1 with device and host support
Low-power sleep and dormant modes
Drag-and-drop programming using mass storage over USB
26 × multi-function GPIO pins
2 × SPI, 2 × I2C, 2 × UART, 3 × 12-bit ADC, 16 × controllable PWM channels
Accurate clock and timer on-chip
Temperature sensor
Accelerated floating-point libraries on-chip
8 × Programmable I/O (PIO) state machines for custom peripheral support
https://github.com/espressif/esp-hosted
ESP-Hosted solution
ESP-Hosted project provides a way to use ESP32 or ESP32-S2 (termed as ESP peripheral) as a communication processor for Wi-Fi and Bluetooth/BLE connectivity. On the host side, ESP-Hosted offers a standard network interface for receiving and transmitting 802.3 frames. On top of the network interface, the host can use its own TCP/IP and TLS stack. For BT connectivity, a standard HCI interface is exposed to the Bluetooth host stack.
Please note that this project doesn't provide a standard 802.11 interface to the host. For the control path between the host and ESP peripheral, ESP-Hosted uses a custom implementation based on Protobuf.
Connectivity Support
ESP hosted solution provides following WLAN and BT/BLE features to host:
WLAN Features:
802.11b/g/n
WLAN Station
WLAN Soft AP
BT/BLE Features:
v4.2 BR/EDR and BLE
Supported Hosts
ESP-Hosted solution supports microprocessors running Linux as well as STM32 MCU (STM32F469I). It's possible to port this relatively easily on other MCUs too. We support Raspberry-Pi (3 Model B+, 4 Model B) and STM32 Discovery Board (STM32F469I-DISCO) out of the box.
Supported Transports
ESP-Hosted uses SDIO or SPI interface as a transport interface for data and control path. The host acts as SDIO or SPI host whereas ESP32 or ESP32-S2 acts as a corresponding ESP peripheral. Currently Raspberry Pi supports both SDIO and SPI transport and STM32 supports SPI transport. As a peripheral device, ESP32 supports both SDIO and SPI transport interfaces and ESP32-S2 supports SPI transport interface.
For detailed explanation, please go through -
Using Raspberry-Pi as a Linux host
Using STM32F469I-DISCO as a MCU host
Feature Matrix
Linux Host
Below table explains which feature is supported on which transport interface for Linux based host.
ESP device Transport Interface WLAN support Virtual serial interface BT/BLE support
ESP32 SDIO Yes Yes Yes
ESP32 SPI Yes Yes Yes
ESP32 UART No No Yes
ESP32-S2 SDIO NA NA NA
ESP32-S2 SPI Yes Yes NA
ESP32-S2 UART No No NA
MCU Host
Below table explains which feature is supported on which transport interface for MCU based host.
ESP device Transport Interface WLAN support Virtual serial interface BT/BLE support
ESP32 SDIO No No No
ESP32 SPI Yes Yes HCI interface can be implemented over virtual serial interface
ESP32 UART No No No
ESP32-S2 SDIO NA NA NA
ESP32-S2 SPI Yes Yes NA
ESP32-S2 UART No No NA
有个开源的命令行工具musicbox可以在线听网易云音乐:
https://whycan.com/t_3114.html
这个版本短板基本补齐了,就是频率不能再高点吗?
https://zhuanlan.zhihu.com/p/340872134
设备端是esp32+sht30,程序源码:
import bluetooth
from ble_advertising import advertising_payload
from micropython import const
from sht30 import SHT30
import json
sensor = SHT30()
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_WRITE = const(3)
_UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
_UART_TX = (
bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),
bluetooth.FLAG_NOTIFY,
)
_UART_RX = (
bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),
bluetooth.FLAG_WRITE,
)
_UART_SERVICE = (
_UART_UUID,
(_UART_TX, _UART_RX,),
)
# org.bluetooth.characteristic.gap.appearance.xml
_ADV_APPEARANCE_GENERIC_COMPUTER = const(128)
class BLEUART:
def __init__(self, ble, name="mpy-uart", rxbuf=100):
self._ble = ble
self._ble.active(True)
self._ble.irq(handler=self._irq)
((self._tx_handle, self._rx_handle,),) = self._ble.gatts_register_services(
(_UART_SERVICE,)
)
# Increase the size of the rx buffer and enable append mode.
self._ble.gatts_set_buffer(self._rx_handle, rxbuf, True)
self._connections = set()
self._rx_buffer = bytearray()
self._handler = None
# Optionally add services=[_UART_UUID], but this is likely to make the payload too large.
self._payload = advertising_payload(name=name, appearance=_ADV_APPEARANCE_GENERIC_COMPUTER)
self._advertise()
def irq(self, handler):
self._handler = handler
def _irq(self, event, data):
# Track connections so we can send notifications.
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _, = data
self._connections.add(conn_handle)
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _, = data
if conn_handle in self._connections:
self._connections.remove(conn_handle)
# Start advertising again to allow a new connection.
self._advertise()
elif event == _IRQ_GATTS_WRITE:
conn_handle, value_handle, = data
if conn_handle in self._connections and value_handle == self._rx_handle:
self._rx_buffer += self._ble.gatts_read(self._rx_handle)
if self._handler:
self._handler()
def any(self):
return len(self._rx_buffer)
def read(self, sz=None):
if not sz:
sz = len(self._rx_buffer)
result = self._rx_buffer[0:sz]
self._rx_buffer = self._rx_buffer[sz:]
return result
def write(self, data):
for conn_handle in self._connections:
self._ble.gatts_notify(conn_handle, self._tx_handle, data)
def close(self):
for conn_handle in self._connections:
self._ble.gap_disconnect(conn_handle)
self._connections.clear()
def _advertise(self, interval_us=500000):
self._ble.gap_advertise(interval_us, adv_data=self._payload)
def demo():
import time
ble = bluetooth.BLE()
uart = BLEUART(ble)
def on_rx():
print("rx: ", uart.read().decode().strip())
uart.irq(handler=on_rx)
#nums = [4, 8, 15, 16, 23, 42]
#i = 0
try:
while True:
temperature, humidity = sensor.measure()
print('Temperature:', temperature, '℃, RH:', humidity, '%')
#uart.write(str(nums[i]) + "\n")
uart.write(json.dumps({"temp":'%.2f' % temperature})) #ble max len 20 bytes
uart.write(json.dumps({"humi":'%.2f' % humidity}))
time.sleep_ms(1000)
except KeyboardInterrupt:
pass
uart.close()
if __name__ == "__main__":
demo()
ble_advertising.py
# Helpers for generating BLE advertising payloads.
from micropython import const
import struct
import bluetooth
# Advertising payloads are repeated packets of the following form:
# 1 byte data length (N + 1)
# 1 byte type (see constants below)
# N bytes type-specific data
_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)
# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
payload = bytearray()
def _append(adv_type, value):
nonlocal payload
payload += struct.pack("BB", len(value) + 1, adv_type) + value
_append(
_ADV_TYPE_FLAGS,
struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
)
if name:
_append(_ADV_TYPE_NAME, name)
if services:
for uuid in services:
b = bytes(uuid)
if len(b) == 2:
_append(_ADV_TYPE_UUID16_COMPLETE, b)
elif len(b) == 4:
_append(_ADV_TYPE_UUID32_COMPLETE, b)
elif len(b) == 16:
_append(_ADV_TYPE_UUID128_COMPLETE, b)
# See org.bluetooth.characteristic.gap.appearance.xml
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
return payload
def decode_field(payload, adv_type):
i = 0
result = []
while i + 1 < len(payload):
if payload[i + 1] == adv_type:
result.append(payload[i + 2 : i + payload[i] + 1])
i += 1 + payload[i]
return result
def decode_name(payload):
n = decode_field(payload, _ADV_TYPE_NAME)
return str(n[0], "utf-8") if n else ""
def decode_services(payload):
services = []
for u in decode_field(payload, _ADV_TYPE_UUID16_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<h", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID32_COMPLETE):
services.append(bluetooth.UUID(struct.unpack("<d", u)[0]))
for u in decode_field(payload, _ADV_TYPE_UUID128_COMPLETE):
services.append(bluetooth.UUID(u))
return services
def demo():
payload = advertising_payload(
name="micropython",
services=[bluetooth.UUID(0x181A), bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")],
)
print(payload)
print(decode_name(payload))
print(decode_services(payload))
if __name__ == "__main__":
demo()
蓝牙数据格式是json的字符串:
{"temp":25.5}
{"humi":27.5}
https://occ.t-head.cn/vendor/detail/index?id=3840454249402605568&vendorId=3706716635429273600&module=1#sticky
有数据手册和应用开发手册,手册信息不是很全。安信可的模组才6.9,这价格也是太给力
这是b站大v的h3核心板,不知道是几层的。
https://github.com/peng-zhihui/Project-Quantum
这个项目是业余玩的,断断续续已经5年。本想再完善一些开源,但是一个人能力和时间有限,而且追逐完美是永无止境的,还是早些开源和大家一起完善。这次公布的资料包括立创eda的工程和全部micropython的源码,以最开放的MIT License开源。对于某些内行来说,pcb和源码还有很多不足,还请大家谅解,也请大家积极的在github(https://github.com/kekemuyu/linewatch)提出issue,这个项目会一直跟进。
作者:wildgeek
https://www.bilibili.com/read/cv8335161
出处: bilibili
f1c100s直接驱动,应该是rgb屏
拆机图
https://whycan.com/t_2608.html
之前看到过一个DoWatch。
http://www.doyoung.net/works/DoWatch/index.html5年了还没完善,确实挺业余的(指的是时间)。
5年还没放弃,也挺不容易的。这5年,可能这些技能作者本身不具备,不断学习成长,也可能这些技术作者本身就会,划了5年水。
中间隔了一两年,没理这个项目,也就是有时间就玩会儿。只是最近把硬件做的比较完善了。项目一直在进化中,
不出意外,下一个版本将会采用f1c200s来做主控。
B站
https://www.bilibili.com/video/BV18a411A7uZ/
从2015开始,经过3个主要版本的迭代,功能从
简单的计时到添加指南针和温度,再到时间自动
同步、天气、指南针、高度计、温湿度、水平仪、
自建应用。不仅仅是硬件的简单堆砌,还有软件
系统的构建,为了LineWatch和未来更多其它硬件
专门开发了应用分发网站https://iotbbs.vip
(正在开发中)和开发文档https://doc.iotbbs.vip。
为了能使手表可以连上wifi,还专门开发了微信小
程序"IOT管家",用手机把wifi的密码发送给手表
就可以联网了。
oled和矩阵键盘驱动直接操作gpio开发(c语言),然后提供接口给go语言调用。
t9输入法参考了原子哥,中文gbk字库也是自己生成。其实可以在linux系统安装中文字库,这样应该更简单。
造轮子:由于oled屏是128*64,输入界面比较特殊。所以用go语言做了几个显示组件,比如列表list、文本框memo,t9拼音输入界面就是组合了list和memo的方法做的。
做这个例子主要是为了总结之前所学,学完就要及时输出,可以更好的查漏补缺。下一步将用go语言和f1c100s开发个更加实用的东西。
硬件:
m328
bm8563
蜂鸣器
11颗led
2个按键
功能基本把bm8563功能全部用上了:
1.日历:包括年月日星期,猜猜是怎么显示的
2.闹钟:可设置小时,分,日,星期闹钟
3.睡眠可按键唤醒,或bm8563闹钟时间到中断唤醒
4.掉电模式电流仅0.4ua
https://www.bilibili.com/video/BV1L54y1C7ax/
https://www.ixigua.com/6882364459222991373?logTag=J8YNnp5VnhKE8GLzt3tbJ
经过两个版本的迭代,解决外壳问题。pcb制作并不难,外壳才是时间杀手。
视频展现了外壳的绘制过程,把将近5G的视频压缩到了3分钟。
另配just blue背景音乐,正符合wildgeek账号的本色。
上视频:
https://www.ixigua.com/6878500453290607112?logTag=E8dVjyJPuOLTkpdJQoY1H
https://m.bilibili.com/video/BV1Dy4y1k7NM
https://whycan.com/t_3148.html这是之前sysbench的测试结果,同样是1G频率,v3s竟然比pizerow还要慢,要知道pizerow可是arm11架构的
这是lvgl的go绑定测试,由于cgo的强大,go语言可以调用lvgl的动态库。
https://github.com/yangyongzhen/golvgl
package main
import (
"golvgl/lvgl"
"log"
"time"
)
func main() {
log.Println("Hello Go,LittlevGL")
lb := lvgl.Label(lvgl.ScrAct(), nil)
lb.SetText("hello world,go test 222")
lb.Align(nil, lvgl.LV_ALIGN_CENTER, 0, 0)
log.Println("Hello Go Over 222")
for true {
lvgl.TickInc(5)
lvgl.TaskHandler()
time.Sleep(5000)
}
}
速度很猛,上下行加起来 200Mbps快到上限了,这是什么测试软件?
专门去找的移植好的demo,可以直接make,主要是 官方的littlevgl的framebuffer移植教程https://blog.lvgl.io/2018-01-03/linux_fb没有makefile文件,对makefile又不熟悉,所以用这个github上的地址https://github.com/helioz2000/lvgl_demo移植版更容易编译,Makefile其实是适用所有linux的framebuffer驱动模式的,稍微修改一下参数即可,树莓派运行littlevgl在tft上的效果:
这是nanopi neo的文档http://wiki.friendlyarm.com/wiki/index.php/NanoPi_NEO/zh中找到的,希望能帮助lz:
首先在chrome安装tampermonkey,然后在tampermonkey里添加以下脚本:
// ==UserScript==
// @icon https://github.githubassets.com/favicon.ico
// @name Github 镜像访问,加速下载
// @namespace https://github.com/jadezi/github-accelerator/
// @version 1.1.1
// @description GitHub 镜像,github 加速
// @author jadezi
// @license GPL License
// @match *://github.com/*
// @require https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @resource mycss https://gitee.com/jadezi/github-accelerator-css/raw/master/index.css
// @grant GM_addStyle
// @grant GM_setClipboard
// @grant GM_getResourceText
// ==/UserScript==
(function() {
var clone = true;
// var clone = false;
var depth = true;
// var depth = false;
var mirror = true;
// var mirror = false;
var hide = false;
var location = window.location.href;
var mirror_url1 = "https://" + "github.com.cnpmjs.org";
var mirror_url2 = "https://" + "hub.fastgit.org";
var mirror_url3 = "https://" + "github.wuyanzheshui.workers.dev";
var download_url1 = "https://download.fastgit.org";
var str1 = "";
if (clone) {
str1 += "git clone ";
if (depth) {
str1 += "--depth=1 ";
}
}
var a = location.split("/");
var str2 = "/" + a[3] + "/" + a[4] + ".git";
var clone_utl1 = str1 + mirror_url1 + str2;
var clone_utl2 = str1 + mirror_url2 + str2;
var str3 = window.location.pathname;
var web_url1 = mirror_url1 + str3;
var web_url2 = mirror_url2 + str3;
var web_url3 = mirror_url3 + str3;
var info = `
<div class="user-ment">
<button class="btn btn-primary" type="button" id="mirror-btn">镜像网址</button>
<div class="collapse multi-collapse" id="collapse">
<div class="user-card user-card-body">
<div class="user-alert user-alert-warning" role="alert">clone、depth命令的插入可手动编辑代码关闭</div>
<div class="user-alert user-alert-danger" style="color: #721c24;background-color: #f8d7da;border-color: #f5c6cb;" role="alert">镜像地址请不要登陆自己的账户,造成损失本人概不负责</div>
<div class="user-input-group user-mb-3">
<div class="user-input-group-prepend"><span class="user-input-group-text" id="inputGroup-sizing-default">快速克隆1:</span></div>
<input id="clone_case_1" type="text" value="${clone_utl1}" data-autoselect="" class="user-form-control" aria-label="将此存储库克隆到 ${clone_utl1}" readonly aria-describedby="inputGroup-sizing-default">
<div class="user-input-group-append">
<button class="btn btn-outline-secondary" type="button" id="button-copy1" data-container="body" data-toggle="popover" data-placement="bottom" data-content="复制成功">复制</button>
</div>
<a type="button" href="${web_url1}" class="btn">快速浏览1</a>
</div>
<div class="user-input-group user-mb-3">
<div class="user-input-group-prepend">
<span class="user-input-group-text" id="inputGroup-sizing-default">快速克隆2:</span>
</div>
<input id="clone_case_2" type="text" value="${clone_utl2}" data-autoselect="" class="user-form-control" aria-label="将此存储库克隆到 ${clone_utl2}" readonly aria-describedby="inputGroup-sizing-default" >
<div class="user-input-group-append">
<button class="btn btn-outline-secondary" type="button" id="button-copy2" data-container="body" data-toggle="popover" data-placement="bottom" data-content="复制成功">复制</button>
</div>
<a type="button" href="${web_url2}" class="btn">快速浏览2</a>
</div>
<div class="user-input-group user-mb-3">
<div class="user-input-group-prepend">
<span class="user-input-group-text" id="inputGroup-sizing-default">快速克隆3:</span>
</div>
<input type="text" data-autoselect="" class="user-form-control" aria-describedby="inputGroup-sizing-default" value="不支持clone,直接跳转--->" aria-label="" readonly="" >
<a type="button" href="${web_url3}" class="btn">快速浏览3</a>
</div>
</div>
</div>
</div>`;
$(".repository-content").prepend(info);
$(".Box.Box--condensed").each(function () {
$(this).find(".d-flex.Box-body>a").each(function () {
var href = $(this).attr("href");
var url1 = download_url1 + href;
var url2 = mirror_url3 + href;
var div1 = `<div class="user_download" style="display: flex;justify-content: flex-end;flex-grow: 1;"><div><a style="padding:4px;" class="btn user-btn-link" href="${url1}" rel="nofollow">快速下载1</a></div><div><a style="padding:4px" class="btn user-btn-link" href="${url2}" rel="nofollow">快速下载2(推荐)</a></div></div>`
$(this).after(div1);
});
$(this).find(".d-block.Box-body>a").each(function () {
var href = $(this).attr("href");
var url1 = download_url1 + href;
var url2 = mirror_url3 + href;
var div1 = `<div class="user_download" style="display: flex;"><div><a style="padding:4px;" class="btn user-btn-link" href="${url1}" rel="nofollow">快速下载1</a></div><div><a style="padding:4px" class="btn user-btn-link" href="${url2}" rel="nofollow">快速下载2(推荐)</a></div></div>`
$(this).after(div1);
});
});
$(".mt-2.d-flex").each(function () {
var url1 = mirror_url3 +"/"+a[3]+"/"+a[4]+ "/archive/master.zip";
var span1 = `<a class="btn btn-outline get-repo-btn btn-block" rel="nofollow" href="${url1}">Fast Download ZIP</a>`;
$(this).after(span1);
});
// 复制按钮
$("#button-copy1").on("click",function(){
GM_setClipboard($("#clone_case_1").val())
alert("复制成功")
})
$("#button-copy2").on("click",function(){
GM_setClipboard($("#clone_case_2").val())
alert("复制成功")
})
// 隐藏面板
$("#mirror-btn").on("click", function () {
if (!hide) {
$("#collapse").hide();
} else {
$("#collapse").show();
}
hide = !hide;
})
function init(){
if (!mirror) {
$("#collapse").hide()
}
}
// 初始化面板
init()
GM_addStyle(GM_getResourceText("mycss"));
})();
然后在访问github时会出现以下界面,直接clone镜像站点即可:
访问速度如下,大概在400~500k/s的样子:
跨平台终端闹钟,多组时间设置,左右箭头选择时间,上下调整时间,空格将设置时间添加到列表。
遍历列表设置的时间,到时控制电脑beep发声,并从列表删除过期时间
https://github.com/kekemuyu/tools/tree/master/timer
字符板的游戏,键盘检测只能在win下,如果在其他系统运行需要修改键盘检测,后期会改进。
snake direction is controled by w,s,a,d .
key detect only apply to windows,later will improve it.
https://github.com/kekemuyu/gogame/tree/master/snake
snake.7z
突然发现自己的github上多了个贡献徽章,开始还不知道是什么意思。今天看到新闻才知道代码被放到了北极。大家晒一下自己的徽章吧。
新闻:https://www.qbitai.com/2020/07/16682.html
刚好之前分析过uboot,自己的bootloader成功启动过kernel,楼主参考下
1.
kernel_entry = (void (*)(int, int, u32))0x80000000;
kernel_entry(0, 0, 0x80c00000);
0x80c00000为DTB地址
2.kernel配置时 bootargs要配置为内置,这样bootloader省事多了
3.kernel dts文件加入内存信息,因为目前kernel内存参数靠uboot写dts传,这里我也是卡住了很久,直到将uboot bootz删减到最小才发现
memory_DDR0@80000000 {
device_type = "memory";
reg = <0x80000000 0x2000000>;
};
现在自己的bootloader使用spi dma读取kernel,启动速度缩短到2.xs液晶进界面
谢谢提醒,可能是内存没初始化,加上试一下。
取sdram地址搞错了,改成如下:
volatile unsigned int *sdram_dtb_start = (volatile unsigned int *)0x80030000;
volatile unsigned int *sdram_kernel_start = (volatile unsigned int *)0x80040000;
// void *sdram_dtb_start = (void *)0x80030000;
// void *sdram_kernel_start = (void *)0x80040000;
启动kernel还有问题,继续。。。
想做一个简易的引导f1c100s的bootloader,查阅了很多资料,最后看了韦东山视频发现做一个简易的引导linux的boot并不难。
简易boot源码https://www.cnblogs.com/blogs-of-lxl/p/5906103.html 。手里正好有tiny200s的板子,所以想在这个板子上移植这个boot。
达克罗德大神的裸奔代码正好可以用上,在这个基础上加上引导代码即可。现在的问题是copy内核到sdram出现问题,卡在了拷贝内核到sdram的过程。如下:
引导代码:
#include <stdint.h>
#include <stdio.h>
#include <string.h>
extern void sys_uart_putc(char c);
extern void sys_uart_print(char *str);
extern void sys_spi_flash_init(void);
extern void sys_spi_flash_exit(void);
extern void sys_spi_flash_read(int addr, void * buf, int count);
static inline void sdelay(int loops)
{
__asm__ __volatile__ ("1:\n" "subs %0, %1, #1\n"
"bne 1b":"=r" (loops):"0"(loops));
}
int boot_main(int argc, char **argv) {
void (*theKernel)(int zero, int arch, unsigned int params);
void *sdram_dtb_start = (void *)0x80030000;
void *sdram_kernel_start = (void *)0x80040000;
/* 0. 从NOR FLASH里把dtb读入内存 */
sys_uart_print("Copy dtb from nor\n\r");
sys_spi_flash_init();
volatile unsigned int spi_dtb_start=0x30000;
sys_spi_flash_read( spi_dtb_start,sdram_kernel_start, 0x10000);
sys_uart_print("Copy dtb from nor ok!\n\r");
/* 1. 从NOR FLASH里把内核读入内存 */
sys_uart_print("Copy kernel from nor\n\r");
volatile unsigned int spi_kernel_start=0x40000;
sys_spi_flash_read(spi_kernel_start, sdram_kernel_start, 0x260000);
sys_uart_print("Copy kernel from nor ok!\n\r");
sys_spi_flash_exit();
/* 2. 设置参数 ,与内核约定参数存放地址,Uboot写个内核的遗嘱^^*/
// puts("Set boot params\n\r");
// setup_start_tag();
// setup_memory_tags();
// setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
// setup_end_tag();
/* 3. 跳转执行 */
sys_uart_print("Boot kernel\n\r");
theKernel = (void (*)(int, int, unsigned int))0x80040000;
theKernel(0, 0, 0x80030000); //362:arm
/*
* mov r0, #0
* ldr r1, =362
* ldr r2, =0x30000100
* mov pc, #0x30008000
*/
sys_uart_print("Error!\n\r");
/* 如果一切正常, 不会执行到这里 */
return 0;
}
问题现象:
以下内容摘自网络,可见uboot跳转到内核前需要设置三个参数,其中第三个参数是传递参数或设备树的。这里有个疑问,第三个参数只能是atags或者是dtb中的一个,不能同时使用,但是为什么荔枝派nano官方的文档中uboot设置既可以用boot.cmd传参数,同时设备数也可以使用?
1. 对于32bit的arm处理器,bootloader启动内核时,会设置r0,r1,r2三个寄存器,
r0一般设置为0;
r1一般设置为machine id (在使用设备树时该参数没有被使用);
r2一般设置ATAGS(使用设备树之前)或DTB的开始地址(使用设备树之后)
RK3308 平时约42度,满载58度左右
https://whycan.cn/files/members/1749/7D0103EE-09E1-41D5-A7F1-141A094752DC.jpeg
这个芯片功耗很低呀,也想玩玩
环境准备https://www.cnblogs.com/kekemuyu/p/13054169.html
rust项目:
1. cargo new hello
执行后会生成hello工程目录
2. cd hello
进入hello目录后,看到Cargo.toml,这是配置文件。然后是src/main.rs
fn main() {
println!("hello arm");
}
3. 编译
cargo build --target=armv5te-unknown-linux-gnueabi
生成可执行文件
target/armv5te-unknown-linux-gnueabi/debug/
或者 target/armv5te-unknown-linux-gnueabi/release/
凑个热闹,用sysbench 测得https://whycan.cn/t_3148.html
顶一下,同样想知道
装chrome了吗? 依赖于chrome浏览器
装了,我电脑就这一个浏览器。
是下载的这个安装包吗?在64位系统试过了,可以的
https://github.com/kekemuyu/gosunxifel/releases/download/v0.0.1/gosunxifel.7z
F:\gosunxifel>gosunxifel.exe
2020/05/07 15:12:47 config.go 44 F://gosunxifel
2020/05/07 15:12:47 main.go 15 Running with CPUs:4
2020/05/07 15:12:47 main.go 19 app-version:v0.0.1
2020/05/07 15:12:47 ui.go 37 exec: "": executable file not found in %PATH%
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x74b159]goroutine 1 [running]:
main.(*Myweb).Run(0xb5ff00)
F:/go_work/src/gosunxifel/ui.go:45 +0x49
main.main()
F:/go_work/src/gosunxifel/main.go:31 +0x95F:\gosunxifel>
装chrome了吗? 依赖于chrome浏览器
上次的mmap版虽然速度提高了不少,但还是有扫描感觉。而且看到晕哥的回复:
这个速度本来就慢,
几十kHz,
内核与用户的数据同步毫秒级。
就是说linux不适合干用gpio直接驱动的事情,即使用mmap也一样。
感觉在用户层不可能再提高速度了,可是最近看到一些帖子说mmap是直接内存映射,不涉及内核层和用户层的交互。
又唤起了对mmap的兴趣,仔细研究了一下我的devmem.c文件发现,发现Writebit函数每次都调用mmap和munmap太浪费时间,其实当时就知道这个需要改但由于懒惰没太在意。这次优化后,oled刷新和裸奔应该没区别了。
源码:https://github.com/kekemuyu/f1c100s
执行depmod:
root@antbian:~/linux_work/test/led# depmod
depmod: WARNING: could not open /lib/modules/4.15.0-rc8-licheepi-nano+/modules.order: No such file or directory
depmod: WARNING: could not open /lib/modules/4.15.0-rc8-licheepi-nano+/modules.builtin: No such file or directory
root@antbian:~/linux_work/test/led# ls /lib/modules/4.15.0-rc8-licheepi-nano+/*
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.alias
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.alias.bin
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.builtin.bin
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.dep
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.dep.bin
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.devname
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.softdep
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.symbols
/lib/modules/4.15.0-rc8-licheepi-nano+/modules.symbols.bin
执行命令modprobe led_device.ko:
root@antbian:~/linux_work/test/led# modprobe led_device.ko
modprobe: ERROR: ../libkmod/libkmod.c:514 lookup_builtin_file()
could not open builtin file '/lib/modules/4.15.0-rc8-licheepi-nano+/modules.builtin.bin'
modprobe: FATAL: Module led_device.ko not found in directory /lib/modules/4.15.0-rc8-licheepi-nano+
最近想研究一下linux驱动的写法,拿出了吃灰的easyarm基于i.mx287。发现周立功的easyarm的教程竟然是基于linux2.6的,设备树都没有。驱动相关教程更是草草的一带而过。
果断弃之,看了一个大神的关于设备树和驱动的视频教程,发现写驱动真是太痛苦了,给所有驱动工程师点赞。
总结一下驱动工程师需要的技能:
0. 驱动模型(驱动整体架构)的了解。
1. linux内核源码需要了解一些。主要是涉及到驱动相关的数据结构和函数。
2. 设备树的结构。 设备树如何匹配linux内核驱动
3. 驱动编写。设备的注册、注销、以及涉及到各种数据结构,linux驱动相关的函数。需要对linux系统有比较深入的了解
4. 内存操作相关。物理地址,虚拟地址,映射关系。以及相关函数的使用
5. cpu芯片寄存器的了解。
6. 驱动测试。这个测试估计也很不好做,只能打log,不像keil可以单步调试看寄存器的值。
这只是两天来的大概的了解,估计更复杂的驱动涉及到东西更多,比如gpu的驱动、音频驱动、网卡驱动等。
linux设备驱动的编写,说白了是linux给你一个框架,你的程序只能在框架中能写。但前提是你要非常熟悉这个框架。
想入门驱动的同学,要做好长期作战的准备。
我用你的uboot.config配置,编译出现错误,是需要修改uboot代码吗?
board/sunxi/built-in.o: In function `setup_environment':
/root/u-boot/board/sunxi/board.c:699: undefined reference to `eth_env_set_enetaddr'
board/sunxi/built-in.o: In function `board_mmc_init':
/root/u-boot/board/sunxi/board.c:488: undefined reference to `sunxi_mmc_init'
cmd/built-in.o: In function `label_boot':
/root/u-boot/cmd/pxe.c:796: undefined reference to `do_bootm'
common/built-in.o: In function `usb_kbd_remove':
/root/u-boot/common/usb_kbd.c:625: undefined reference to `stdio_deregister_dev'
arm-linux-gnueabi-ld.bfd: BFD (Linaro_Binutils-2017.11) 2.28.2.20170706 assertion fail /home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/snapshots/binutils-gdb.git~users~linaro~binutils-2_28-branch/bfd/elf32-arm.c:9514
arm-linux-gnueabi-ld.bfd: BFD (Linaro_Binutils-2017.11) 2.28.2.20170706 assertion fail /home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/snapshots/binutils-gdb.git~users~linaro~binutils-2_28-branch/bfd/elf32-arm.c:9514
arm-linux-gnueabi-ld.bfd: BFD (Linaro_Binutils-2017.11) 2.28.2.20170706 assertion fail /home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/snapshots/binutils-gdb.git~users~linaro~binutils-2_28-branch/bfd/elf32-arm.c:9514
arm-linux-gnueabi-ld.bfd: BFD (Linaro_Binutils-2017.11) 2.28.2.20170706 assertion fail /home/tcwg-buildslave/workspace/tcwg-make-release/builder_arch/amd64/label/tcwg-x86_64-build/target/arm-linux-gnueabi/snapshots/binutils-gdb.git~users~linaro~binutils-2_28-branch/bfd/elf32-arm.c:9514
Makefile:1261: recipe for target 'u-boot' failed
make: *** [u-boot] Error 1
上次是用文件方式操作io,这次换成了设备地址映射到虚拟地址,操作虚拟地址来操作io。但是这两种方式驱动oled都非常慢,有很明显的扫描感。不知道大家用什么方式操作f1c100s的io,理论上不应该这么慢的。
https://github.com/kekemuyu/f1c100s/tree/master/oled_spi
mmap部分代码:
#include"devmem.h"
int tempfd;
void Openfile(){
if((tempfd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
}
void Closefile(){
close(tempfd);
}
void Writebit(long target,int bitsize ,char value){
void *map_base, *virt_addr;
unsigned long read_result, writeval;
int fd;
fd = fcntl(tempfd, F_DUPFD, 0);
if(fd<0){
FATAL;
}
// if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
// printf("/dev/mem opened.\n");
// fflush(stdout);
/* Map one page */
map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
if(map_base == (void *) -1) FATAL;
// printf("Memory mapped at address %p.\n", map_base);
// fflush(stdout);
virt_addr = map_base + (target & MAP_MASK);
read_result = *((unsigned long *) virt_addr);
// printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result);
// fflush(stdout);
// printf("bitsize:%d;value:%d\n",bitsize,value);
if(value==0){
read_result&=~(1<<bitsize);
}else{
read_result|=1<<bitsize;
}
writeval=read_result;
*((unsigned long *) virt_addr)=writeval;
read_result=*((unsigned long *) virt_addr);
// printf("Written 0x%X; readback 0x%X\n", writeval, read_result);
// fflush(stdout);
if(munmap(map_base, MAP_SIZE) == -1) FATAL;
close(fd);
}
尝试用go语言操作gpio驱动oled,驱动方式是spi,io操作方式是文件方式。由于这种方式需要不断写文件,oled刷新有点慢。后期会改成mmap方式。
https://github.com/kekemuyu/f1c100s/tree/master/oled_spi
oled 部分代码:
package oled
import (
"oled_spi/gpio"
"time"
)
const (
OLED_CLK = "gpio131"
OLED_DI = "gpio132"
OLED_RST = "gpio133"
OLED_DC = "gpio138"
OLED_CS = "gpio139"
OLED_CMD = 0 //写命令
OLED_DATA = 1 //写数据
SIZE = 16
Max_Column = 128
Max_Row = 64
)
func Init() {
gpio.OpenGpioFile(OLED_CLK)
gpio.OpenGpioFile(OLED_DI)
gpio.OpenGpioFile(OLED_RST)
gpio.OpenGpioFile(OLED_DC)
gpio.OpenGpioFile(OLED_CS)
SetRst()
time.Sleep(time.Millisecond * 100)
ClrRst()
time.Sleep(time.Millisecond * 100)
SetRst()
WriteByte(0xAE, OLED_CMD) //--turn off oled panel
WriteByte(0x00, OLED_CMD) //---set low column address
WriteByte(0x10, OLED_CMD) //---set high column address
WriteByte(0x40, OLED_CMD) //--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
WriteByte(0x81, OLED_CMD) //--set contrast control register
WriteByte(0x66, OLED_CMD) // Set SEG Output Current Brightness
WriteByte(0xA1, OLED_CMD) //--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
WriteByte(0xC8, OLED_CMD) //Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
WriteByte(0xA6, OLED_CMD) //--set normal display
WriteByte(0xA8, OLED_CMD) //--set multiplex ratio(1 to 64)
WriteByte(0x3f, OLED_CMD) //--1/64 duty
WriteByte(0xD3, OLED_CMD) //-set display offset Shift Mapping RAM Counter (0x00~0x3F)
WriteByte(0x00, OLED_CMD) //-not offset
WriteByte(0xd5, OLED_CMD) //--set display clock divide ratio/oscillator frequency
WriteByte(0x80, OLED_CMD) //--set divide ratio, Set Clock as 100 Frames/Sec
WriteByte(0xD9, OLED_CMD) //--set pre-charge period
WriteByte(0xF1, OLED_CMD) //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
WriteByte(0xDA, OLED_CMD) //--set com pins hardware configuration
WriteByte(0x12, OLED_CMD)
WriteByte(0xDB, OLED_CMD) //--set vcomh
WriteByte(0x40, OLED_CMD) //Set VCOM Deselect Level
WriteByte(0x20, OLED_CMD) //-Set Page Addressing Mode (0x00/0x01/0x02)
WriteByte(0x02, OLED_CMD) //
WriteByte(0x8D, OLED_CMD) //--set Charge Pump enable/disable
WriteByte(0x14, OLED_CMD) //--set(0x10) disable
WriteByte(0xA4, OLED_CMD) // Disable Entire Display On (0xa4/0xa5)
WriteByte(0xA6, OLED_CMD) // Disable Inverse Display On (0xa6/a7)
WriteByte(0xAF, OLED_CMD) //--turn on oled panel
WriteByte(0xAF, OLED_CMD) /*display ON*/
Clear()
SetPos(0, 0)
}
func SetClk() {
gpio.GpioNSetValue(OLED_CLK, "1")
}
func ClrClk() {
gpio.GpioNSetValue(OLED_CLK, "0")
}
func SetDi() {
gpio.GpioNSetValue(OLED_DI, "1")
}
func ClrDi() {
gpio.GpioNSetValue(OLED_DI, "0")
}
func SetRst() {
gpio.GpioNSetValue(OLED_RST, "1")
}
func ClrRst() {
gpio.GpioNSetValue(OLED_RST, "0")
}
func SetDc() {
gpio.GpioNSetValue(OLED_DC, "1")
}
func ClrDc() {
gpio.GpioNSetValue(OLED_DC, "0")
}
func SetCs() {
gpio.GpioNSetValue(OLED_CS, "1")
}
func ClrCs() {
gpio.GpioNSetValue(OLED_CS, "0")
}
func WriteByte(dat, cmd byte) {
if cmd != 0 {
SetDc()
} else {
ClrDc()
}
ClrCs()
for i := 0; i < 8; i++ {
ClrClk()
if dat&0x80 != 0 {
SetDi()
} else {
ClrDi()
}
SetClk()
dat <<= 1
}
SetCs()
SetDc()
}
func SetPos(x, y byte) {
WriteByte(0xb0+y, OLED_CMD)
WriteByte(((x&0xf0)>>4)|0x10, OLED_CMD)
WriteByte((x&0x0f)|0x01, OLED_CMD)
}
func Clear() {
for i := byte(0); i < 8; i++ {
WriteByte(0xb0+i, OLED_CMD) //设置页地址(0~7)
WriteByte(0x00, OLED_CMD) //设置显示位置—列低地址
WriteByte(0x10, OLED_CMD) //设置显示位置—列高地址
for n := 0; n < 128; n++ {
WriteByte(0, OLED_DATA) //更新显示
}
}
}
func ShowChar(x, y, chr byte) {
c := chr - ' ' //得到偏移后的值
if x > Max_Column-1 {
x = 0
y = y + 2
}
if SIZE == 16 {
SetPos(x, y)
for i := 0; i < 8; i++ {
WriteByte(F8X16[int(c)*16+i], OLED_DATA)
}
SetPos(x, y+1)
for i := 0; i < 8; i++ {
WriteByte(F8X16[int(c)*16+i+8], OLED_DATA)
}
} else {
SetPos(x, y+1)
}
}
func ShowString(x, y byte, chrs string) {
for _, v := range []byte(chrs) {
ShowChar(x, y, v)
x += 8
if x > 120 {
x = 0
y += 2
}
}
}
zero.licheepi文档中操作gpio的方法,放在这里备用
使用sysfs操作GPIO的例子:
#echo 192 > /sys/class/gpio/export #导出 PG0, GREEN
#ls /sys/class/gpio/
export gpio192 gpiochip0 unexport
#ls /sys/class/gpio/gpio192/
active_low direction subsystem/ value device/ power/ uevent
#echo "out" > /sys/class/gpio/gpio192/direction #设置为输出
#echo 0 > /sys/class/gpio/gpio192/value #亮灯
#echo 1 > /sys/class/gpio/gpio192/value #灭灯
#echo "in" > /sys/class/gpio/gpio192/direction #设置为输入
#cat /sys/class/gpio/gpio192/value #读取电平
0
You mean in the past or currently ?
In the past: semiconductors, components, PCBs., motors, 3D printer parts, various welding accessories, IP camera modules etc.
Currently, I have not purchased anything yet. I was thing about ordering some PCBs, again semiconductors, capacitors, resistors, probably some PCBs. I was also considering getting one Kendryte K210 EVB and few modules. In your opinion, which option is better: Widora’s BITK210, Sipeed MAIX Dock K210, Allwinner R329, other MCU/SoC with AI ? I spoke lately with Allwinner about R329. I will not be available for at least 3 months.
you can try to order pcbs at https://jlcpcb.com/,this company is famous about making pcbs in chnia and other counties.
semiconductors,you can try at taobao.com.
ai modules,k210 chip is nice. all this things you can get at taobao.
mcuzone发布了rk3308的功耗测试。我自己实测了一下,结果基本一致。单核功耗大致是56mA*5v=280mW
ARM发布cortex A35的时候宣称28nm工艺下1GHz功耗是90mW。莫非这300MHz的频率,要多出190mW的功率?在linux下如何把rk3308的频率设置在1GHz恒定?有办法调整cpu核心电压么?
另外, 有rk3308板的网友,可否也帮忙测试下?
你测的是核心板的功耗,3308本身应该没这么大功耗。不得不说rk3308的能耗比还是挺厉害的
想试试attiny13能否驱动spi的320*135的ips高清屏,没想到真的成功了,一直担心1k的flash不够用,看来是完全没问题.
Program Memory Usage : 716 bytes 69.9 % Full
Data Memory Usage : 0 bytes 0.0 % Full
源码是从stm32移植的,没怎么整理,将就看吧,开发环境是atmel官方的avr studio7
/*
* lcd.c
*
* Created: 2020/3/27 22:27:25
* Author : Administrator
*/
#include <avr/io.h>
#include <util/delay.h>
//»±ÊÑÕÉ«
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //רɫ
#define BRRED 0XFC07 //רºìÉ«
#define GRAY 0X8430 //»ÒÉ«
#define DARKBLUE 0X01CF //ÉîÀ¶É«
#define LIGHTBLUE 0X7D7C //dzÀ¶É«
#define GRAYBLUE 0X5458 //»ÒÀ¶É«
#define LIGHTGREEN 0X841F //dzÂÌÉ«
#define LGRAY 0XC618 //dz»ÒÉ«(PANNEL),´°Ìå±³¾°É«
#define LGRAYBLUE 0XA651 //dz»ÒÀ¶É«(Öмä²ãÑÕÉ«)
#define LBBLUE 0X2B12 //Ç³×ØÀ¶É«(Ñ¡ÔñÌõÄ¿µÄ·´É«)
#define USE_HORIZONTAL 2 //ÉèÖúáÆÁ»òÕßÊúÆÁÏÔʾ 0»ò1ΪÊúÆÁ 2»ò3ΪºáÆÁ
#define LCD_W 240
#define LCD_H 135
#define LCD_SCLK_Clr() PORTB&=0xfe//SCL=SCLK
#define LCD_SCLK_Set() PORTB|=0x01
#define LCD_MOSI_Clr() PORTB&=0xfd//SDA=MOSI
#define LCD_MOSI_Set() PORTB|=0x02
#define LCD_RES_Clr() PORTB&=0xfb//RES
#define LCD_RES_Set() PORTB|=0x04
#define LCD_DC_Clr() PORTB&=0xf7//DC
#define LCD_DC_Set() PORTB|=0x08
#define LCD_CS_Clr() PORTB&=0xef//CS
#define LCD_CS_Set() PORTB|=0x10
int main(void)
{
LCD_Init();
LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
LCD_DrawPoint(20,20,WHITE);
/* Replace with your application code */
while (1)
{
LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
LCD_Fill(0,0,LCD_W,LCD_H,GREEN);
LCD_Fill(0,0,LCD_W,LCD_H,RED);
}
}
void LCD_GPIO_Init(void){
DDRB=0xFF;
PORTB=0xff;
}
/******************************************************************************
º¯Êý˵Ã÷£ºLCD´®ÐÐÊý¾ÝдÈ뺯Êý
Èë¿ÚÊý¾Ý£ºdat ҪдÈëµÄ´®ÐÐÊý¾Ý
·µ»ØÖµ£º ÎÞ
******************************************************************************/
void LCD_Writ_Bus(uint8_t dat)
{
uint8_t i;
LCD_CS_Clr();
for(i=0;i<8;i++)
{
LCD_SCLK_Clr();
if(dat&0x80)
{
LCD_MOSI_Set();
}
else
{
LCD_MOSI_Clr();
}
LCD_SCLK_Set();
dat<<=1;
}
LCD_CS_Set();
}
void LCD_WR_REG(uint8_t dat){
LCD_DC_Clr();//дÃüÁî
LCD_Writ_Bus(dat);
LCD_DC_Set();//дÊý¾Ý
}
void LCD_WR_DATA8(uint8_t dat){
LCD_Writ_Bus(dat);
}
void LCD_Init(void)
{
LCD_GPIO_Init();//³õʼ»¯GPIO
LCD_RES_Clr();//¸´Î»
_delay_ms(100);
LCD_RES_Set();
_delay_ms(100);
LCD_WR_REG(0x11);
_delay_ms(120);
LCD_WR_REG(0x36);
if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00);
else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0);
else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70);
else LCD_WR_DATA8(0xA0);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x33);
LCD_WR_REG(0xB7);
LCD_WR_DATA8(0x35);
LCD_WR_REG(0xBB);
LCD_WR_DATA8(0x19);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x2C);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x12);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x20);
LCD_WR_REG(0xC6);
LCD_WR_DATA8(0x0F);
LCD_WR_REG(0xD0);
LCD_WR_DATA8(0xA4);
LCD_WR_DATA8(0xA1);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2B);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x54);
LCD_WR_DATA8(0x4C);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x0B);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x23);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0xD0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x0C);
LCD_WR_DATA8(0x11);
LCD_WR_DATA8(0x13);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x3F);
LCD_WR_DATA8(0x44);
LCD_WR_DATA8(0x51);
LCD_WR_DATA8(0x2F);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x1F);
LCD_WR_DATA8(0x20);
LCD_WR_DATA8(0x23);
LCD_WR_REG(0x21);
LCD_WR_REG(0x29);
}
/******************************************************************************
º¯Êý˵Ã÷£ºLCDдÈëÊý¾Ý
Èë¿ÚÊý¾Ý£ºdat дÈëµÄÊý¾Ý
·µ»ØÖµ£º ÎÞ
******************************************************************************/
void LCD_WR_DATA(uint16_t dat)
{
LCD_Writ_Bus(dat>>8);
LCD_Writ_Bus(dat);
}
/******************************************************************************
º¯Êý˵Ã÷£ºÉèÖÃÆðʼºÍ½áÊøµØÖ·
Èë¿ÚÊý¾Ý£ºx1,x2 ÉèÖÃÁÐµÄÆðʼºÍ½áÊøµØÖ·
y1,y2 ÉèÖÃÐÐµÄÆðʼºÍ½áÊøµØÖ·
·µ»ØÖµ£º ÎÞ
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
if(USE_HORIZONTAL==0)
{
LCD_WR_REG(0x2a);//ÁеØÖ·ÉèÖÃ
LCD_WR_DATA(x1+52);
LCD_WR_DATA(x2+52);
LCD_WR_REG(0x2b);//ÐеØÖ·ÉèÖÃ
LCD_WR_DATA(y1+40);
LCD_WR_DATA(y2+40);
LCD_WR_REG(0x2c);//´¢´æÆ÷д
}
else if(USE_HORIZONTAL==1)
{
LCD_WR_REG(0x2a);//ÁеØÖ·ÉèÖÃ
LCD_WR_DATA(x1+53);
LCD_WR_DATA(x2+53);
LCD_WR_REG(0x2b);//ÐеØÖ·ÉèÖÃ
LCD_WR_DATA(y1+40);
LCD_WR_DATA(y2+40);
LCD_WR_REG(0x2c);//´¢´æÆ÷д
}
else if(USE_HORIZONTAL==2)
{
LCD_WR_REG(0x2a);//ÁеØÖ·ÉèÖÃ
LCD_WR_DATA(x1+40);
LCD_WR_DATA(x2+40);
LCD_WR_REG(0x2b);//ÐеØÖ·ÉèÖÃ
LCD_WR_DATA(y1+53);
LCD_WR_DATA(y2+53);
LCD_WR_REG(0x2c);//´¢´æÆ÷д
}
else
{
LCD_WR_REG(0x2a);//ÁеØÖ·ÉèÖÃ
LCD_WR_DATA(x1+40);
LCD_WR_DATA(x2+40);
LCD_WR_REG(0x2b);//ÐеØÖ·ÉèÖÃ
LCD_WR_DATA(y1+52);
LCD_WR_DATA(y2+52);
LCD_WR_REG(0x2c);//´¢´æÆ÷д
}
}
/******************************************************************************
º¯Êý˵Ã÷£ºÔÚÖ¸¶¨ÇøÓòÌî³äÑÕÉ«
Èë¿ÚÊý¾Ý£ºxsta,ysta ÆðÊ¼×ø±ê
xend,yend ÖÕÖ¹×ø±ê
color ÒªÌî³äµÄÑÕÉ«
·µ»ØÖµ£º ÎÞ
******************************************************************************/
void LCD_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
{
uint16_t i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//ÉèÖÃÏÔʾ·¶Î§
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA(color);
}
}
}
void LCD_DrawPoint(uint16_t x,uint16_t y,uint16_t color)
{
LCD_Address_Set(x,y,x,y);//ÉèÖùâ±êλÖÃ
LCD_WR_DATA(color);
}
不知道你是安装的什么系统,我是在v3s上跑了debian系统,然后用apt来安装的mpg123.甚至安装了musicbox,可以在线听网易云音乐.请看我的连接
https://whycan.cn/t_3114.html
激光雷达可能满足lz的要求,只是提供思路,lz的精度要求太高估计价格都得是6位数,以下是我搜到的自动驾驶的例子
https://item.taobao.com/item.htm?spm=a230r.1.14.22.560648b3JdxsV2&id=591094709862&ns=1&abbucket=18#detail
显示ip,mac,设备名称
https://github.com/kekemuyu/tools/tree/master/ipscan
测试环境:
1.板子是自己画的,模块是esp32-wroom-32
2.测量工具福禄克15B+
datasheet功耗参数:
实测功耗:
1.deepsleep 10ua
2. 仅有ulp工作(控制一个io反转) 330ua
这里只评测ulp的工作状态功耗,ulp在8mhz主频工作时功耗仅有330ua(和手册的150ua还有不少的差距,暂时找不到原因),平均功耗是41ua/mhz.
这个成绩已经是相当牛逼了。如果真能到达手册说的150ua,平均工作功耗是20ua/mhz,几乎逆天级别了。而且在ulp中可以操作io,i2c,adc,定时器等常用外设,适用于功耗要求特别严格的场景,唯一的缺点是ulp现在只能汇编。
实验用例(arduino):
https://whycan.cn/files/members/1315/ulp_gpio.7z
其他国外大佬能获取更多资料。
The F1C100s needs some additional work to enable its Cedar peripheral.
I’ve asked Allwinner for more info about the F1C100s’s video stack, and I plan to continue working on it in the meantime as well.
All this means that you could be playing 1080P HD video on Linux on a 61-cent chip. Absolutely crazy.
估计不是硬件问题,micropython对wifi支持的不太稳定,我的esp32温度采集用arduino做的已经稳定运行几个月了,https://kekemuyu.com/device
Your text here
不再需要假装,哈哈哈哈哈哈哈哈哈
翻译都太生硬,还不如看原版
看到晕哥在帮大家下载github项目,我也凑个热闹,让阿里云也发挥点余热。用golang做了个github项目下载代理服务,使用方法是:
http://kekemuyu.com:8080? 后面加上github项目地址,比如 https://github.com/kekemuyu/tools 。
完整地址是: http://kekemuyu.com:8080?https://github.com/kekemuyu/tools
下载有点慢,大家谅解,我的阿里云是国内的,没有梯子。tools里有代理服务的源码
牛啊, 我顺手上传上来了: gosunxifel_20200110.7z
请问下楼主下一个版本能不能把 V3s 也加上?
感谢上传,如有需求会加的
哈哈,多种语言版本,lz是c#,我的是go,还有其它语言版本吗?
go版本https://whycan.cn/t_3540.html
是通过调用 sunxi-fel.exe 进程吗?如何获取进度的? pipe 管道吗?
是调用 sunxi-fel.exe ,go标准库有调用外部程序的功能。
cmd := exec.Command("cmd.exe", "/c", rootdir+"/sunxi-tools-win32support_f1c100s/sunxi-fel.exe -p spiflash-write "+addr+" "+file)
out, err := cmd.CombinedOutput()
err = cmd.Run()
log.Debug(err, string(out))
if err != nil {
fmt.Println(err)
}
花了点时间用go+h5把sunxi-tools打包成图形化操作的,比cmd命令方便点。
https://github.com/kekemuyu/gosunxifel
需要明确一件事,把设备树和linux内核加载到ram后,只要把设备树地址赋值给r2寄存器,然后跳转到linux地址就可以了吗?linux就会自动解析设备树了吗?
内核对设备树的处理也是分这三部分的。
1. 对于32bit的arm处理器,bootloader启动内核时,会设置r0,r1,r2三个寄存器,
r0一般设置为0;
r1一般设置为machine id (在使用设备树时该参数没有被使用);
r2一般设置ATAGS(使用设备树之前)或DTB的开始地址(使用设备树之后)
bootloader给内核传递的参数时有2种方法:ATAGS 或 DTB
a. __lookup_processor_type : 使用汇编指令读取CPU ID, 根据该ID找到对应的proc_info_list结构体(里面含有这类CPU的初始化函数、信息)
b. __vet_atags : 判断是否存在可用的ATAGS或DTB
c. __create_page_tables : 创建页表, 即创建虚拟地址和物理地址的映射关系
d. __enable_mmu : 使能MMU, 以后就要使用虚拟地址了
e. __mmap_switched : 上述函数里将会调用__mmap_switched
f. 把bootloader传入的r2参数, 保存到变量__atags_pointer中
g. 调用C函数start_kernel
head.S/head-common.S :
把bootloader传来的r1值, 赋给了C变量: __machine_arch_type
把bootloader传来的r2值, 赋给了C变量: __atags_pointer // dtb首地址
对于32bit的arm处理器,machine_desc 使用 MACHINE_START 初始化,其 dt_compat 存储的是 compatible 属性数组,用于表示支持的单板。
u-boot 中也提供的对dtb文件进行操作的命令,为 fdt, uboot 中所有的命令都是使用U_BOOT_CMD()来定义的,对应文件中有命令的使用注释。
需要传递一个tag列表或设备树地址给内核,简化的bootloader做到4kb以内都很正常
感谢回复,很有帮助。做一个简单的boot,从start.s文件中找到一段关键代码:
/* Initial system clock, ddr add uart */
bl sys_clock_init
bl sys_dram_init
bl sys_uart_init
/* Copyself to link address */
adr r0, _start
ldr r1, =_start
cmp r0, r1
beq 1f
bl sys_copyself
这段代码几乎是核心引导了,加上copy linux内核代码应该就可以了,然后跳转到linux内核地址
又弄了个nat123,
看看速度对比一下http://dika.ren
是 nat123的
http://www.dika.ren
免费frp的
我研究过frp的源码,穿透软件基本没什么可优化的了,主要瓶颈在网络
https://whycan.cn/files/members/3/2019-12-25_152909.png
这里修改 bootcmd/bootargs 默认参数, 早期版本的u-boot不能用make menconfig 修改这两个参数。
是修改的这里,这个bad crc应该不影响启动时间,也不影响引导系统。这里uboot启动时间大部分都花在了sf probe 0 60000000; sf read 0x80c00000 0x70000 0x10000; sf read 0x80008000 0x80000 0x400000; bootz 0x80008000 - 0x80c00000
这个read应该是把spiflash中的内容读到dram里的过程,这里需要优化,方法是:减小内核和文件系统体积,我先试试内核1m,文件系统1m时的情况
希望能秒启动linux,所以从uboot开始优化。
1.启动顺序是否可配置
2.这个bad crc是什么情况
3.SF: Detected w25q128bv with page size 256 Bytes, erase size 4 KiB, total 16 MiB 这条log后具体做了什么,足足停顿了3~4s
U-Boot SPL 2018.01-05676-g0018878-dirty (Dec 25 2019 - 03:05:37)
DRAM: 64 MiB
Trying to boot from MMC1
Card did not respond to voltage select!
mmc_init: -95, time 22
spl: mmc init failed with error: -95
Trying to boot from sunxi SPI
U-Boot 2018.01-05676-g0018878-dirty (Dec 25 2019 - 03:05:37 +0000) Allwinner Technology
CPU: Allwinner F Series (SUNIV)
Model: Lichee Pi Nano
DRAM: 64 MiB
MMC: SUNXI SD/MMC: 0
SF: Detected w25q128bv with page size 256 Bytes, erase size 4 KiB, total 16 MiB
*** Warning - bad CRC, using default environment
In: serial@1c25000
Out: serial@1c25000
Err: serial@1c25000
Net: No ethernet found.
starting USB...
No controllers found
Hit any key to stop autoboot: 0
SF: Detected w25q128bv with page size 256 Bytes, erase size 4 KiB, total 16 MiB
device 0 offset 0x70000, size 0x10000
SF: 65536 bytes @ 0x70000 Read: OK
device 0 offset 0x80000, size 0x400000
SF: 4194304 bytes @ 0x80000 Read: OK
=>
你可以试试用这个汇编进入类似于休眠状态,但功耗也不会非常低。
__asm__ __volatile__("mcr p15, 0, %0, c7,c0,4" :: "r"(0));
这是ARM926EJ-S手册上提到的 Dynamic power management (wait for interrupt mode) 。我只简单试了一下,在我的板子上低了10mA。没试过唤醒:D。
感谢分享,我看手册上还有个Static power management (leakage control),这个试过吗?