页次: 1
晶振就频率,电压,封装引脚, 这3条对得上就行。
ppm看不同应用,但有源晶振基本没太差的。
我同事贴的应该是这个 https://item.szlcsc.com/30858.html
@usbbios 这个硬件有人发车吗? 想搭个车。
或新开1趟车?
做回来了,体验挺好的,软件直接把68013的烧录和fpga的烧录全做了,不用额外安装软件和下载器。
同样还是这个软件,直接扔Wireshark里面就能抓包。
显示的内容也比较全,好在可以使用Wireshark的过滤器过滤掉不需要显示的内容。
!(usbll.pid == 0x69) IN
!(usbll.pid == 0x5a) NAK
!(usbll.pid == 0xa5) SOF
!(syslog.msg == "USB PHY error") && !(usbll.invalid_pid) && !(usbll.pid == 0x5a) && !(usbll.pid == 0xa5) && !(usbll.pid == 0x69)
ARM的MMU和CACHE在一起,为了开CACHE,MMU也必须开。
但可以像RT-Thread那样,虽然开了,但做1:1映射就行。
注意cache只对ddr部分开启,外设部分不开。
RISC-V的大部分芯片,MMU和CACHE分开的,可以不开MMU只开CACHE
当然CACHE也可以不开,但用DDR的话会卡成狗。
可以直接用坛友移植好的: https://whycan.com/t_3958.html
RT-Thread主仓库的bsp也可以用: https://gitee.com/rtthread/rt-thread/tree/v4.0.x/bsp/allwinner_tina
PLL出来也是整百的,24还是25好像关系不大。楼主是哪个外设要多少频率?
你看下这个
求一份全志f1c100s的8080接口的lcd驱动 https://whycan.com/t_6744.html
f1c100s/200s的串口波特率最大是多少? https://whycan.com/t_4673.html
楼主的USB HOST 实现了吗。我最近也在调试USB HOST MSC
目标
给T113-S3适配RT-Thread,并支持SMP。
资料
没有太详细的资料和示例,只有一些零星的信息。
- F133封装基本兼容
- Cortex-A7双核
一些参考资料
- https://whycan.com/t_7808.html
- https://bbs.aw-ol.com/topic/1247/
计划
- 最好能直接使用xfel在SRAM,或是DDR中运行,避免从SD卡启动还需要SPL。
- 先用xfel payload跑通, 最好能有串口打印。
- 再尝试直接load到ddr运行。
- 尝试在DDR中运行rt-thread
- 尝试响应中断
- 尝试支持SPL
过程
环境准备
- 开发板 芒果派
- 下载工具 xfel
先连接好开发板,默认没卡也没有FLASH,会自动进入USB FEL。
通过xfel可以探测并读取芯片信息。
$ xfel version
AWUSBFEX ID=0x00185900(R528/T113) dflag=0x44 dlength=0x08 scratchpad=0x00045000
$ xfel sid
d3402000ec1408140140082114cb5bcb
$ xfel ddr t113-s3
Initial ddr controller succeeded
xfel payload
磨刀不误砍柴工,调芯片最好有JTAG,没有的情况下,串口打印是必须的。
xfel工程里面有默认有t113-s3的ddr和spi的payload工程了。
我们先从里面剥离出最简单的串口操作代码,让其至少有输出功能,方便后面打印日志。
使用新编译出的payload,重新编译生成xfel,再随便执行下spi flash命令,串口有打印就行了。
留着这代码备用。
ddr中运行代码
继续基于上面的代码,把具体的功能可以先屏蔽。然后把修改链接地址为ddr。
然后使用xfel把这代码加载到DDR中,运行下看没有输出。
xfel ddr t113-s3
xfel write 0x40000000 spi.bin
xfel exec 0x40000000
果然看到了打印,说明可以使用xfel直接加载程序到DDR中运行,这样为后面的开发带来了极大的便利。
DDR中运行rt-thread
有了基本开发条件后,就可以开始移植软件部分了。
因为是cortex-a的内核,这块都比较通用,我打算基于`bsp/qemu-vexpress-a9`来修改。
先是使用menuconfig重新配置一下,把所有用不到的组件全关了,只留最基本的kernal和串口驱动部分。
再把链接脚本中的地址修改为目标芯片的地址 0x40000000。
然后把board.c中的中断和时钟心跳这些与硬件有关的代码先屏蔽。
串口驱动
因为没有JTAG,那么串口驱动是必须的了, 把之前从xfel payload中提取出来的串口驱动复制过来。
替换到原来的串口驱动的初始化部分,并把原来的所有硬件相关的代码暂时屏蔽。
只保留putc功能。
编译通过后,使用xfel加载到ddr中运行。观察串口。
果然没有任何打印 !!!!
汇编中的debug
遇事不要慌,问题肯定不大。没有任何打印说明程序没能正常运行,或是打印本身有问题。
首先没被运行的可能性可以排除,因为之前加载payload改的小代码可以运行的。
然后就是有可能程序还没运行到程序中串口初始化的地方,此时最好能有JTAG单步,或是能知道启动代码中的汇编程序都运行到哪了。
如果是C,每行加个打印就好了。嗯,汇编也能加。
因为驱动中的接口都是一堆参数,带句柄,还是static的,显然不方便汇编里面调用。
于是我们单独改造下,让串口初始化不需要参数,输出函数只要一个输出数据参数即可。
void sys_uart_init(void)
{
virtual_addr_t addr;
uint32_t val;
/* Config GPIOE2 and GPIOE3 to txd0 and rxd0 */
addr = 0x020000c0 + 0x0;
val = readl(addr);
val &= ~(0xf << ((2 & 0x7) << 2));
val |= ((0x6 & 0xf) << ((2 & 0x7) << 2));
write32(addr, val);
............
}
void sys_uart_putc(char c)
{
virtual_addr_t addr = 0x02500000;
while((readl(addr + 0x7c) & (0x1 << 1)) == 0);
write32(addr + 0x00, c);
}
这样汇编中就可以比较方便调用了,先放在启动入口看看有没打印。
.globl _reset
_reset:
ldr r1, [r1]
bl sys_uart_init
mov r0, ='R'
bl sys_uart_putc
mov r0, ='T'
bl sys_uart_putc
mov r0, ='T'
bl sys_uart_putc
新程序加载到DDR中,果然看到了我们想要的RTT这3个字的打印。说明程序运行到了这里。
通过这种办法,继续在汇编中不同位置添加不同的字符,最后定位到是进MMU初始化就再没打印了。
哦!!! 想起来还没更新MMU配置呢。
MMU配置可以先简单些,32位的全4G空间全部当成外设,把DDR区域设置为常规(带cache,可运行)
修改board.c中的platform_mem_desc表就好了
struct mem_desc platform_mem_desc[] = {
{0x00000000, 0xFFFFFFFF, 0x00000000, DEVICE_MEM},
{0x40000000, 0x47FFFFFF, 0x40000000, NORMAL_MEM},
};
更新mmu配置后,果然看到了 RT-Thread 启动LOGO,还打印了`msh>`。
当然,此时命令行不能输入。因为我们串口驱动的输入还没写。
因为全志的串口驱动基本兼容的,知道串口外设的基地址,直接抄原来其它芯片的代码,直接读寄存器,把getc实现就好了。
但还是不能输入,应该是要支持中断才行。
中断
cortex-A芯片一般都使用GIC,但有好几个版本,通过有限的资料查到,T113-S3是使用GICv2。
这块代码都是通用的,关键是要知道其在芯片中的地址,这个PDF中也有查到GIC地址是在`0x03020000`。
RT-Thread中,GICv2的基本适配已做好,新芯片适配需要知道2个地址,但PDF中没写。
这块根据全志同类型芯片的偏移来看,猜测是一样的
/* the basic constants and interfaces needed by gic */
rt_inline rt_uint32_t platform_get_gic_dist_base(void)
{
return 0x03021000;
}
rt_inline rt_uint32_t platform_get_gic_cpu_base(void)
{
return 0x03022000;
}
再通过PDF上面查到的UART0中断号是34,改好后,加载运行,果然收到中断了。
SMP
接下来就是适配SMP了,因为只是2核,所以也不用管分簇这些了。
最主要是要知道第2个核是怎么启动,启动后会运行哪个地址的程序。
其它这里还有个坑点要注意,就是有些芯片多核是自动启动的,但此时一般软件环境还没准备好,可能会乱飞,需要把非0核先暂停下来。
如果是这类芯片,就需要把`RT_SMP_AUTO_BOOT`打开,这样非0核会自动挂起,直到被0核唤醒,再去指定地址运行。
因为我们之前都能正常运行了,所以肯定不是这种类型的。
通过 https://whycan.com/t_7808.html 这个贴子里面 shaoxi2010 大佬的说明,知道了第2个核的启动方法。
此时更新menuconfig把SMP打开,然后更新下SMP需要的几个接口
/*
The Soft Entry Address Register of CPU0 is 0x070005C4.
The Soft Entry Address Register of CPU1 is 0x070005C8.
*/
void rt_hw_secondary_cpu_up(void)
{
uint32_t cpuboot_membase = 0x070005c4;
uint32_t cpuxcfg_membase = 0x09010000;
uint32_t cpu, reg;
cpu = 1;
/* Set CPU boot address */
writel((uint32_t)(secondary_cpu_start), cpuboot_membase + 4 * cpu);
/* Deassert the CPU core in reset */
reg = readl(cpuxcfg_membase);
writel(reg | (1 << cpu), cpuxcfg_membase);
__asm__ volatile ("isb":::"memory");
}
一些和芯片外设相关的先禁用掉,不要心跳也是能运行的。
void secondary_cpu_c_start(void)
{
// int timer_irq_number;
// timer_irq_number = aw_get_irq_num("TIMER1");
rt_hw_vector_init();
rt_hw_spin_lock(&_cpus_lock);
arm_gic_cpu_init(0, platform_get_gic_cpu_base());
// arm_gic_set_cpu(0, timer_irq_number, 0x2); //timer1
// timer1_init();
// rt_hw_interrupt_install(timer_irq_number, rt_hw_timer1_isr, RT_NULL, "tick1");
// rt_hw_interrupt_umask(timer_irq_number);
rt_system_scheduler_start();
}
编译通过后,使用xfel加载到ddr中运行。SMP果然愉快地运行起来了。
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Apr 9 2022 21:17:55
2006 - 2022 Copyright by RT-Thread team
[I/sal.skt] Socket Abstraction Layer initialize success.
cpuxcfg_membase = 0x13FF0101 // 启动之前的值
cpuxcfg_membase = 0x13FF0103 // 启动之后的值
Hello T113 RT-Thread SMP!
msh />ps
thread cpu bind pri status sp stack size max used left tick error
-------- --- ---- --- ------- ---------- ---------- ------ ---------- ---
tshell 0 2 20 running 0x00000140 0x00001000 15% 0x0000000a 000
aio N/A 2 16 suspend 0x00000080 0x00000800 07% 0x0000000a 000
sys work N/A 2 23 suspend 0x00000084 0x00000800 06% 0x0000000a 000
tsystem N/A 2 30 suspend 0x00000098 0x00000400 22% 0x00000020 000
tidle1 1 1 31 running 0x0000005c 0x00000400 19% 0x00000020 000
tidle0 N/A 0 31 ready 0x0000005c 0x00000400 19% 0x00000020 000
timer N/A 2 4 suspend 0x0000007c 0x00000400 12% 0x0000000a 000
后续
整理代码上gitee
@shaoxi2010 谢谢大佬!SMP启动成功
/*
The Soft Entry Address Register of CPU0 is 0x070005C4.
The Soft Entry Address Register of CPU1 is 0x070005C8.
*/
void rt_hw_secondary_cpu_up(void)
{
uint32_t cpuboot_membase = 0x070005c4;
uint32_t cpuxcfg_membase = 0x09010000;
uint32_t reg;
/* Set CPU boot address */
writel((uint32_t)(secondary_cpu_start), cpuboot_membase + 1 * 4);
/* Deassert the CPU core in reset */
reg = readl(cpuxcfg_membase);
writel(reg | (1 << 1), cpuxcfg_membase);
reg = readl(cpuxcfg_membase);
__asm__ volatile ("isb":::"memory");
}
\ | /
- RT - Thread Operating System
/ | \ 4.1.0 build Apr 9 2022 21:17:55
2006 - 2022 Copyright by RT-Thread team
[I/sal.skt] Socket Abstraction Layer initialize success.
cpuxcfg_membase = 0x13FF0101 // 启动之前的值
cpuxcfg_membase = 0x13FF0103 // 启动之后的值
Hello T113 RT-Thread SMP!
msh />ps
thread cpu bind pri status sp stack size max used left tick error
-------- --- ---- --- ------- ---------- ---------- ------ ---------- ---
tshell 0 2 20 running 0x00000140 0x00001000 15% 0x0000000a 000
aio N/A 2 16 suspend 0x00000080 0x00000800 07% 0x0000000a 000
sys work N/A 2 23 suspend 0x00000084 0x00000800 06% 0x0000000a 000
tsystem N/A 2 30 suspend 0x00000098 0x00000400 22% 0x00000020 000
tidle1 1 1 31 running 0x0000005c 0x00000400 19% 0x00000020 000
tidle0 N/A 0 31 ready 0x0000005c 0x00000400 19% 0x00000020 000
timer N/A 2 4 suspend 0x0000007c 0x00000400 12% 0x0000000a 000
指ngff接口? 这篇博文写得很详细 https://blog.csdn.net/greless/article/details/51698662
@sniper
在楼主位我的PR链接那里可以看到我的完整代码的,在这个分支 https://github.com/aozima/xfel/tree/aozima_sd
欢迎继续改造。另外你也是直接在板上焊接SD-NAND吗?
也可以试试这位大佬的方法,我暂时文件不大,还没空测试。
https://bbs.aw-ol.com/topic/1002/
可以对比下这个贴子 https://whycan.com/t_7592.html
因芯片本身没加密,所以至少SPL那阶段是不加密的。
你可以程序起来后,根据ID自己算一份,然后自己把自己给更新了。
VMware也可以调优下: VMware虚拟机共享windows目录性能调优小技巧
在使用F133,板子是用的128MB的SD-NAND。然后就遇到烧录问题,因为之前开发板都是拔卡下来烧录的,现在焊上面没法拔,看到xfel添加了spi nand的支持,所以想着在xfel中添加sd的支持也是可以的。
代码已发PR,但因速度不够快,估计不会合并进主干。所以单独发个编译好的exe方便有需要用到的小伙伴。
下载:
xfel-sd_v1.2.4-0c87477d-259075.zip
目前支持多块读写,速度有260KB左右,烧录柿饼固件10MB以下还是够用了。
启来后剩下的资源用SPI WIFI来下载,不过WIFI也就1MB左右,快不到多少。所以调试时要烧录128MB也是可以等等。。。
使用方法(格式基本和FLASH一样,不过内部把length对齐到了8KB):
xfel sd - Detect sd card
xfel sd read <address> <length> <file> - Read sd card to file
xfel sd write <address> <file> - Write file to sd card
相关贴子
- PR 添加SD卡命令
- XFEL已支持spi nand flash烧写
- V3s/S3/f1c100s通过USB启动Linux,并把SD NAND/TF卡挂载为U盘, 可以dd或Win32DiskImager任烧写
有在windows上面使用VMware Player虚拟机,并使用使用vmhgfs挂载windows上面的目录,使用上倒是挺方便。
但是编译大些的项目,相比虚拟机里面的linux上面ext4文件系统就慢多了。
现在调整了一缓存相关的参数,快多了。以编译F133的工程为例,原来2分半,现在20秒。
具体参数细节可以再自己研究调整下。
当然,有了缓存意味着2边同步的时间会变长,不过我的应用主要是在win上面编写和调试。linux里面用docker主要做编译工作,所以两边不会对同一个文件进行读写,且两边切换是手动的,过程至少也要几秒,所以问题不大。
$ vmhgfs-fuse -h
$ vmhgfs-fuse .host:/ /mnt/hgfs -o subtype=vmhgfs-fuse,allow_other,entry_timeout=3,negative_timeout=3,attr_timeout=3,auto_cache
测试好后建议直接写到`/etc/fstab`中
$ cat /etc/fstab
...
.host:/ /mnt/hgfs fuse.vmhgfs-fuse allow_other,entry_timeout=3,negative_timeout=3,attr_timeout=3,defaults 0 0
vm+vmhgfs 默认参数
$ vmhgfs-fuse .host:/ /mnt/hgfs -o subtype=vmhgfs-fuse,allow_other
$ time scons -j12
real 2m27.556s
user 0m35.779s
sys 0m46.991s
vm+vmhgfs 调整参数
$ vmhgfs-fuse .host:/ /mnt/hgfs -o subtype=vmhgfs-fuse,allow_other,entry_timeout=3,negative_timeout=3,attr_timeout=3,auto_cache
$ time scons -j12
real 0m20.262s
user 0m50.965s
sys 0m21.402s
vm+ext4
$ time scons -j12
real 0m9.358s
user 1m4.950s
sys 0m19.415s
#if (LWIP_TCP_KEEPALIVE == 0)
#error "LWIP_TCP_KEEPALIVE must enable"
#endif
rt_err_t socket_config(void)
{
int keepalive = 1; //Enable keepalive.
int keepidle = 60; //idle time is 60s.
int keepinterval = 5; //sending interval of detective packet
int keepcount = 3; //detective count.
int flag = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive)) < 0)
{
LOG("set Keep-Alive attribute failed\n");
return -RT_ERROR;
}
setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle));
setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval));
setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount));
setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flag , sizeof(flag));
return RT_EOK;
}
{
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
setsockopt(connected, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
}
从 https://github.com/u-boot/u-boot.git clone了代码。
确认其中有对应的tag,然后切到这个tag
git clone https://github.com/u-boot/u-boot.git
git tag -l -n | grep v2020.07
git checkout -b aozima v2020.07
把补丁复制到repo根目录,然后检查补丁是否冲突。
# 查看patch的情况
git apply --stat 0001-v2020.07.3.patch
# 检查patch是否能够打上,如果没有任何输出,则说明无冲突,可以打上
git apply --check 0001-v2020.07.3.patch
# git diff生成的patch,用以下命令打上
git apply 0001-v2020.07.3.patch
重新配置编译后,测试1bit的TF卡可以启动。
可以的 sunxi.org 网站有专门一个TF卡固件,插入TF卡,强制进入FEL
简单找了下没找到,可以发个定位不?
不过我自己改了个,也可以用 https://whycan.com/t_6768.html
分享一个专门的TF卡固件,插入TF卡,强制进入FEL,适于F1C100S,应该也适用说F1C200S。
看站长在 https://whycan.com/t_2072.html 时说已有,找不太熟悉没找到。
所以我基于 https://whycan.com/t_4606.html 的工程改了一下,烧录到TF卡可以进入FEL,然后再读写FLASH。
F1C100S_back_to_fel.zip
把这个文件烧录到FLASH0地址也能进入FEL,
当然,把FLASH的0埴写个错文件进去也能进FEL。
--- a/spl/src/sys-copyself.c
+++ b/spl/src/sys-copyself.c
void sys_copyself(void)
{
+ back_to_fel();
+
int d = get_boot_device();
void * mem;
这个有谁试过可以在F1C100S上面启动不? 我烧录后无法启动,还是跑去SPI FLASH上面了。
不过我烧录可以F1C100S在FLASH上面启动的SPL到TF上,还是无法启动。
用的是这个工程 https://whycan.com/t_1393.html
但是TF卡里面直接烧录完整的uboot+linux镜像是可以启动的。
确认TF卡的8K位置,已经完整烧录mksunxi处理过后的SPL BIN文件了。
且这个SPL BIN烧到SPI FLASH的0地址是可以启动的。
不知道TF卡还有什么其它的要求?
比如SPL的大小不能少于多少KB?
我想使用CH579做一个网卡,SPI从机转以太网。
对芯片做了验证,基本上可行。现在遇到了2个问题。
1 SPI从机通过 COUNT=SPI0_DMA_NOW-SPI0_DMA_BEG,
在数据长度大于8字节时,无法获取传输长度。
实际传输大于8字节时,依然只显示7或8,但接收时内存中的数据是对的。
发送时,逻辑分析仪抓到的数据也是对的。
这点是否有解决办法?
没有的话,只能通过数据包头和校验来判定了。
不过芯片好像没有单独的硬件CRC,要用软件来算了。
另外吐槽下,就是SPI从机只能单双工,不过这也还能忍。
2 自己初始化以太网时,交换机灯不亮。
因为不需要在CH579里面跑协议栈,所以打算不要 CH57xNET.LIB
所以根据数据手册和 CH57xNET_LibInit 重写了以太网初始化。
但发现自己写的初始化,PHY好像没有工作,交换机的灯没有亮。
dump出PHY的寄存器发现有区别。
自己写的初始化代码如下
int ch57x_eth_init(const uint8_t *macaddr)
{
uint8_t tmp;
// 配置安全寄存器进入安全模式,打开以太网络的时钟和电源;
// 最好能关中断,因为只有16个周期有效果
R8_SAFE_ACCESS_SIG = 0x57;
R8_SAFE_ACCESS_SIG = 0xA8;
R8_SLP_CLK_OFF1 &= ~(1<<5); // 打开时钟
R8_SLP_POWER_CTRL &= ~(1<<1); // 打开电源
R8_SAFE_ACCESS_SIG = 0;
// 补充,建议这里做个反初始化,防止意外。
// 2 开启相应的中断,可选的,启用阻抗匹配电阻;
// R8_ETH_EIE = RB_ETH_EIE_RXERIE | RB_ETH_EIE_TXERIE | RB_ETH_EIE_R_EN50 | RB_ETH_EIE_TXIE | RB_ETH_EIE_LINKIE | RB_ETH_EIE_RXIE;
R8_ETH_EIE = 0; // 参考反汇编
tmp = R8_ETH_EIE; // 这里回读为0
PRINT("\r\n@%s L=%d, R8_ETH_EIE read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
tmp |= 0xdb; // 1101 1011 参考反汇编
R8_ETH_EIE = tmp; // 参考反汇编
tmp = R8_ETH_EIE; // 这里回读为 0xDB
PRINT("@%s L=%d, R8_ETH_EIE read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
tmp |= 4; // 0b100 50电阻 参考反汇编
R8_ETH_EIE = tmp; // 参考反汇编
tmp = R8_ETH_EIE; // 这里回读为 0xDF
PRINT("@%s L=%d, R8_ETH_EIE read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
R8_ETH_EIR = 0xFF; // 参考反汇编
tmp = R8_ETH_ESTAT;
tmp |= 0xC0; //清中断和buf中断
R8_ETH_ESTAT = tmp;// 参考反汇编写回
tmp = R8_ETH_ECON2;
// PRINT("@%s L=%d, R8_ETH_ECON2 read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
tmp >>= 4;
tmp <<= 4; // 清理低4位
R8_ETH_ECON2 = tmp;
tmp = R8_ETH_ECON2;
// PRINT("@%s L=%d, R8_ETH_ECON2 read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
tmp |= 4;
R8_ETH_ECON2 = tmp;
tmp = R8_ETH_ECON2;
// PRINT("@%s L=%d, R8_ETH_ECON2 read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
tmp = R8_ETH_ECON1;
PRINT("@%s L=%d, R8_ETH_ECON1 read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
tmp |= 0xC0; // 复位发送和接收模块
R8_ETH_ECON1 = tmp;
tmp = R8_ETH_ECON1;
PRINT("@%s L=%d, R8_ETH_ECON1 read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
//清高2位后,再写回
tmp &= 0x3F; // 取消复位状态
R8_ETH_ECON1 = tmp;
tmp = R8_ETH_ECON1;
PRINT("@%s L=%d, R8_ETH_ECON1 read out=%02X\r\n", __FUNCTION__, __LINE__, tmp);
R8_ETH_ERXFCON = 0;
tmp = R8_ETH_MACON1;
tmp |= 1; // MAC 接收使能
R8_ETH_MACON1 = tmp;
tmp = R8_ETH_MACON2;
tmp &= 0x1F; //清高3位后,再写回 RB_ETH_MACON2_PADCFG
R8_ETH_MACON2 = tmp;
tmp = R8_ETH_MACON2;
tmp |= 0x20; // 所有短包填充 0 至 60 字节,再 4字节 CRC;
R8_ETH_MACON2 = tmp;
tmp = R8_ETH_MACON2;
tmp |= 0x10; // 硬件填充 CRC
R8_ETH_MACON2 = tmp;
tmp = R8_ETH_MACON2;
tmp &= 0xfb; // 1111 1011 清除 巨型帧
R8_ETH_MACON2 = tmp;
tmp = R8_ETH_MACON2;
tmp |= 0x01; // 全双工
R8_ETH_MACON2 = tmp;
R16_ETH_MAMXFL = 0x24f; // 0x24f 1500 最大包长,需要确定
// 3 配置接收过滤模式、CRC 功能、MAC 地址;
// R8_ETH_ECON2 = 0x07; // 默认值 0x06,但读出来为4。
R32_ETH_HTL = 0x65820294;
R32_ETH_HTH = 0x220B1858;
// 设置MAC地址
// R32_ETH_MAADRL = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16) | (macaddr[3] << 24);
// R16_ETH_MAADRH = macaddr[4] | (macaddr[5] << 8);
{
uint8_t *ptr = (uint8_t *)&R32_ETH_MAADRL;
uint32_t value;
uint32_t i;
PRINT("mac ptr = %p\r\n", ptr);
for(i=0; i<6; i++)
{
tmp = *macaddr;
PRINT("mac #%d = %02X\r\n", i, tmp);
*ptr = tmp;
ptr++;
macaddr++;
}
value = R32_ETH_MAADRL;
PRINT("R32_ETH_MAADRL: 0x%08X\r\n", value);
value = R16_ETH_MAADRH;
PRINT("R16_ETH_MAADRH: 0x%04X\r\n", value);
}
// R32_ETH_MACON = 0x10310100; //直接用最终值,后面再做分解。
R8_ETH_ECON1 |= RB_ETH_ECON1_RXEN; // 收发控制,测试用
// 4 设置缓存;
R16_ETH_ERXST = (uint32_t)ch57x_rx_buf;
// 5 启动接收,开启中断。
R8_ETH_EIE |= RB_ETH_EIE_INTIE;
return 0;
}
Ceva xm4 DSP开发心得
https://www.jianshu.com/p/591b06993be2
1. 编译和链接时加 -mthumb-interwork
2. 跳转时,先跳到自动生成的 xx_from_thumb 和 xx_from_arm
b1f0c: 002a movs r2, r5
b1f0e: 0020 movs r0, r4
b1f10: f018 ff2a bl cad68 <__memmove_from_thumb> // 当前在thumb模式,调用arm模式的函数
000cad68 <__memmove_from_thumb>: // 编译器自动生成的 interwork 代码
cad68: 4778 bx pc
cad6a: 46c0 nop ; (mov r8, r8)
cad6c: eaffc71a b bc9dc <memmove>
000bc9dc <memmove>:
bc9dc: e1500001 cmp r0, r1
bc9e0: e92d4070 push {r4, r5, r6, lr}
....
bca48: e8bd4070 pop {r4, r5, r6, lr}
bca4c: e12fff1e bx lr
136ac: e1a05000 mov r5, r0
136b0: e1a00004 mov r0, r4
136b4: eb02ddd3 bl cae08 <__rt_ota_get_fw_version_from_arm> // 当前在ARM模式,调用thumb模式的函数
000cae08 <__rt_ota_get_fw_version_from_arm>:
cae08: e59fc000 ldr ip, [pc] ; cae10 <__rt_ota_get_fw_version_from_arm+0x8>
cae0c: e12fff1c bx ip
cae10: 000b9261 // 实际是 000b9260 thumb模式要奇数,用bx实现 跳转+切换
000b9260 <rt_ota_get_fw_version>:
b9260: b510 push {r4, lr}
b9276: bd10 pop {r4, pc}
3. ARM模式的汇编函数,需要添加 `.type xxx, %function`,否则由thumb模式下跳转过来时不会生成`__func_asm_arm_from_thumb`
asm.S
.code 32
.globl _exit
_exit:
b .
.type func_asm_arm, %function
.globl func_asm_arm
func_asm_arm:
BX LR
.code 16
.thumb_func
.globl func_asm_thumb
func_asm_thumb:
BX LR
原文链接 https://blog.csdn.net/zerglurker/article/details/39451123?utm_source=blogxgwz1
>这其实是一个误解,因为 长跳转是由两条跳转指令组成的。
=======================================================
最近因为工作的原因,经常接触到长跳转指令,但是总是弄不明白,跳转的目标地址怎么得来的
经过多方面的资料查找,和自己的反复推算,现在总算弄明白了
先上例子:
下面是几个实际遇到的机器码机器对应的反汇编
示例一 3950a4: f13d feaa =>bl 4d2dfc
示例二 395082: f13d fe40 =>bl 4d2d06
示例三 395044: F7FF FFAc =>bl 394fa0
大家是不是也奇怪为什么16位的thumb指令里面,会出现32位的指令。
开始我也是这么认为的
这其实是一个误解,因为 长跳转是由两条跳转指令组成的。
其实际机器码和和含义如下:
1 1 1 1 0 +11位地址偏移高位(off0)
0xF 13D
1 1 1 1 1 +11位地址偏移低位(off1)
0xF EAA
还是以上述三个例子做示范,
其偏移如下:(偏移是将指令去除高五bit得来的,f13d->13d 高五bit是1111 0【001】||| feaa->6aa高五bit是1111 1【110】)
示例一 off0=0x13d off1=0x6aa
示例二 off0=0x13d off1=0x640
示例三 off0=0x7FF off1=0x7AC
首先要做的事情是将两个11位合并为一个22位数(注意由于off1是11位,意味着其最高位为off0的最低位,off0的值要除2)
即 offmid = ((off0/2)<<12)|((off0%2)<<11)|(off1)
按照这样计算,几个示例的偏移中间量为:
offmid = 0x9eeaa
offmid = 0x9ee40
offmid = 0x3fffac
接着将这个值乘2,得到一个23位数
offmid1 = 0x13dd54
offmid1 = 0x13dc80
offmid1 = 0x7fff58
对于前面两个这是一个正数,最高位为0,所以不必取反保留原来的值
对于最后一个,最高位为1,是负数,要减1后取反
处理后,如下:
offmid2 = 0x13dd54
offmid2 = 0x13dc80
offmid2 = 0x8000a8
最高位为1,则表示向前跳转,最高位为0表示向后跳转
跳转的基址是当前指令的末尾,需要再追加4个字节
所以实际跳转值就是:
off = 0x3950a4+4+0x13dd54 = 0x4d2dfc
off = 0x395082+4+0x13dc80 = 0x4d2d06
off = 0x395044+4- 0x0000a8 = 0x394fa0
反过来再看一看,其实 长跳转的偏移是这么来的:
首先取当前位置和目标位置的偏移差
地址因为内存对齐的原因,必然是偶数(即最低位必然为0),所以偏移值只有23位有意义,最低位永远为0
又由于最高位为符号位,所以,只有22位存储了真正的值
然后取补码(正数的补码是源码,负数的补码是符号位不变,剩余数取反加1),这样可以去除符号位对值的影响,将结果变为一个真正的22位值
最后再将其拆分为两个11位数,分成两个跳转指令执行
这么一想,顺着看,结果一目了然;但是反汇编的时候,难度就大大增加了,呵呵
————————————————
版权声明:本文为CSDN博主「52编程」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/zerglurker/article/details/39451123
无意间搜网上有人拆机玩
https://www.mydigit.cn/forum.php?mod=viewthread&tid=246340
Q3420P芯片,摄像头不知道多少像素的。
我也买了一个收藏。
看到已经玩起来了 https://club.rt-thread.org/ask/article/2720.html
感觉做些辅助或传感器很合适。
用 00:11:22:33:44:55 吧,
或这样
/* OUI 00-80-E1 STMICROELECTRONICS. */
stm32_eth_device.dev_addr[0] = 0x00;
stm32_eth_device.dev_addr[1] = 0x80;
stm32_eth_device.dev_addr[2] = 0xE1;
/* generate MAC addr from 96bit unique ID (only for test). */
stm32_eth_device.dev_addr[3] = *(rt_uint8_t *)(UID_BASE + 4);
stm32_eth_device.dev_addr[4] = *(rt_uint8_t *)(UID_BASE + 2);
stm32_eth_device.dev_addr[5] = *(rt_uint8_t *)(UID_BASE + 0);
能用个P,这刚好是个组播地址。
有很大概率被有组播策略的交换机丢弃,能过的都是不标准的。
广播地址是全为1,即 FF:FF:FF:FF:FF:FF 这个大家都知道。
组播/多播地址是是第48位为1,后面的位与IP地址有换算关系(具体看相关资料)
测试时,建议前3字节使用网卡芯片厂家的OUI,后3字节自己生成,局域网中不重复即可。
正式产品,是需要购买OUI的。
>arp -a
224.0.0.2 01-00-5e-00-00-02 静态
224.0.0.22 01-00-5e-00-00-16 静态
224.0.0.251 01-00-5e-00-00-fb 静态
224.0.0.252 01-00-5e-00-00-fc 静态
239.255.255.250 01-00-5e-7f-ff-fa 静态
255.255.255.255 ff-ff-ff-ff-ff-ff 静态
>netsh interface ipv6 show neighbors
ff02::1 33-33-00-00-00-01 永久
ff02::2 33-33-00-00-00-02 永久
ff02::1:2 33-33-00-01-00-02 永久
ff02::1:3 33-33-00-01-00-03 永久
ff02::1:ff00:86b 33-33-ff-00-08-6b 永久
ff02::1:ff0e:8497 33-33-ff-0e-84-97 永久
ff02::1:ff22:6d50 33-33-ff-22-6d-50 永久
看一下Apicula项目,全开源的Gowin流程。
https://github.com/YosysHQ/
https://github.com/YosysHQ/apicula
赞一个!
原文链接:https://club.rt-thread.org/ask/article/2439.html
工作中的嵌入式项目,基本都是C语言。
一直想在项目中引入一个略高级的语言,来填补C语言的一些不足。
之前有用过MicroPython)和javascript,但除了性能和体积外,都有些要把主要工作转到新语言的感觉,要做不少的对接工作。
也用过Lua,感觉也差不多。
学习评估Rust)语言时,感觉性能和体积应该都不会有太大的问题。加上语言本身主打的安全性,再结合一些库,用来做一些C语言不擅长的动态操作感觉比较合适。
但如果把主要工作切过来,感觉Rust目前又太荒芜了,而且上面的问题也同样存在。
## 尝试
了解到Rust可以编译成静态库,于是动了只用Rust实现其中一小部分功能的想法。
随手一搜,找到这篇文章: c语言调用rust库函数]
按步骤做完,倒是挺顺利,增强了信心。
### 编译arm版静态库
上面测试都是在x86上面进行的,嵌入式基本是使用arm和riscv等芯片。
考虑到上手门槛,我这里选择了[qemu-vexpress-a9](https://gitee.com/rtthread/rt-thread/tree/master/bsp/qemu-vexpress-a9)这个bsp做为我们的目标平台。
这样不用开发板就可以测试了。
先要安装目标环境,可以参考这个链接:Rust 嵌入式开发 STM32 和 RISC-V)
rustup target list
rustup target add armv7a-none-eabi
rustup target list | grep installed
安装好目标环境后,开始尝试编译arm版的静态库
$ cat src/lib.rs
#[no_mangle]
pub extern "C" fn foo(a: i32, b: i32) {
println!("hello : a + b = {}", a + b);
}
$ cargo build --target=armv7a-none-eabi
warning: unused manifest key: build
Compiling foo v0.1.0 (/home/aozima/work/rust_study/foo)
error[E0463]: can't find crate for `std`
|
= note: the `armv7a-none-eabi` target may not be installed
error: aborting due to previous error
For more information about this error, try `rustc --explain E0463`.
error: could not compile `foo`
To learn more, run the command again with --verbose.
查了一些资料
* https://forge.rust-lang.org/release/platform-support.html
* https://blog.csdn.net/readlnh/article/details/88899586
对于没有移植标准库的目标环境,需要添加 `#![no_std]`
$ cat src/lib.rs
#![no_std]
#[no_mangle]
pub extern "C" fn foo(a: i32, b: i32) {
println!("hello : a + b = {}", a + b);
}
这下错误提示变成了
`cannot find macro `println` in this scope`
考虑到先简单做测试,于是先注释掉打印,改为纯运算。
$ cat src/lib.rs
#![no_std]
#[no_mangle]
pub extern "C" fn foo(a: i32, b: i32) -> i32 {
//println!("hello : a + b = {}", a + b);
return a+b;
}
这下错误提示变成了
`error: `#[panic_handler]` function required, but not found`
参考资料:独立式可执行程序,添加必要的 `panic`
$ cat src/lib.rs
#![no_std]
use core::panic::PanicInfo;
#[no_mangle]
pub extern "C" fn foo(a: i32, b: i32) -> i32 {
//println!("hello : a + b = {}", a + b);
return a+b;
}
#[panic_handler]
fn panic(_info:&PanicInfo) -> !{
loop{}
}
终于成功编译
$ cargo build --target=armv7a-none-eabi
warning: unused manifest key: build
Compiling foo v0.1.0 (/home/aozima/work/rust_study/foo)
Finished dev [unoptimized + debuginfo] target(s) in 0.10s
$ ls target/armv7a-none-eabi/debug/libfoo.a
## 使用静态库
把编译出来的 libfoo.a 复制到 qemu-vexpress-a9的`applications/libs`目录下,
并更新 `applications/SConscript`
-group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
+LIBS = ["libfoo.a"] # 添加静态库文件
+LIBPATH = [os.path.join(GetCurrentDir(), 'libs')] # 添加静态库搜索路径
+
+group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH, LIBS = LIBS, LIBPATH = LIBPATH)
### C中引用静态库中的函数
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
extern int foo(int a, int b); // 声明一个函数
int main(void)
{
int tmp;
printf("hello rt-thread\n");
tmp = foo(1, 2);
printf("call rust fn: foo(1, 2) == %d\n", tmp);
return 0;
}
在链接时发生报了错误
$ scons --verbose
... -Lapplications\libs -lfoo -lc -lm
/armv7-ar/thumb\libgcc.a(_arm_addsubdf3.o): In function `__aeabi_ul2d':
(.text+0x304): multiple definition of `__aeabi_ul2d'
applications\libs\libfoo.a(compiler_builtins-9b744f6fddf5e719.compiler_builtins.20m0qzjq-cgu.117.rcgu.o):
/cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.35/src/float/conv.rs:143: first defined here
提示在rust的静态库libfoo.a中也有__aeabi_ul2d的实现,与libgcc.a中冲突。
这点暂时没理解得太清楚,不过release版本编译的库没有引入这个实现
$ cargo build --target=armv7a-none-eabi --release
$ ls target/armv7a-none-eabi/release/libfoo.a
把release版的libfoo.a复制到`applications/libs`目录下,
再次编译链接通过
$ scons --verbose
... -Lapplications\libs -lfoo -lc -lm
arm-none-eabi-objcopy -O binary rtthread.elf rtthread.bin
arm-none-eabi-size rtthread.elf
text data bss dec hex filename
593317 5212 85056 683585 a6e41 rtthread.elf
scons: done building targets.
在qemu中运行成功
\ | /
- RT - Thread Operating System
/ | \ 4.0.3 build Dec 26 2020
2006 - 2020 Copyright by rt-thread team
lwIP-2.0.2 initialized!
hello rt-thread
call rust fn: foo(1, 2) == 3
msh />
## 体积与性能分析
把生成的elf进行反汇编
60010040 <main>:
60010054: fa01f69b blx 6008dac8 <puts>
60010058: e3a01002 mov r1, #2
6001005c: e3a00001 mov r0, #1
60010060: eb01f2ea bl 6008cc10 <foo>
6008cc10 <foo>:
6008cc10: e0810000 add r0, r1, r0
6008cc14: e12fff1e bx lr
可以看到,纯运算类的体积与性能,与C版本完全一致,
其它高级特性可能会对堆的使用较多,但只要遵守rust的规范,写穿溢出的可能性应该极小。
纯运算和对栈的使用,应该不会有太大的差异。
用的模块,自己配10寸大屏来放的,不过画面没有全屏放。
https://item.taobao.com/item.htm?id=586627082894
目前已支持RT-THREAD的spi框架
https:https://whycan.cn/t_5199.html
感谢分享
技术上可以做到。
MMU映射时,1:1映射1片无CACHE的空间。
这样正常出来的内存地址,做一下地址转换就行了。
参考
const struct mem_desc platform_mem_desc[] = {
{0x00000000, 0x03FFFFFF, 0x00000000, NORMAL_MEM}, /* DDR 64M */
{0x10000000, 0x13FFFFFF, 0x00000000, DEVICE_MEM}, /* 加这行 DDR 64M non-cache */
{0xB0000000, 0xB3FFFFFF, 0xB0000000, DEVICE_MEM}, /* IO 64M */
{0xFFF00000, 0xFFFFFFFF, 0xFFF00000, DEVICE_MEM}, /* SYS 1M */
};
但是
内存操作带CACHE,再刷cache.
性能远远高于无cache直接操作的。
为了避免断线,可以考虑使用screen来执行命令。
先设置一下screen配置,在/etc/screenrc末尾添加如下内容。
```shell
caption always "%{.bW}%-w%{.rW}%n %t%{-}%+w %=%H %Y-%m-%d %c %p"
```
这样screen的终端最下面有显示标签,方便辨认。
screen常用命令
screen -list
列出所有会话
screen -dmS name
新建一个会话,后面是会话名称
screen -d name
强制断开一个会话,用户于其它用户连接了某个会话,但他断网,要很长时间才能自动断开。
screen -r name
登入某个会话
在会话中,按住ctrl,依次再按a,d, 就可以安全离开这个会话,里面的命令继续执行。
裴讯,是认真的么?怎么替换,app自己写的么,替换后有什么新发现吗?
昨天晚上收拾桌子,发现吃灰的板子。
刚好看到这个贴子,所以做了一个初步的版本,欢迎入坑 & pr。
找到选项了,参考 https://whycan.cn/t_2939.html
一直有了解到 sigrok 的开源逻辑分析仪项目,但一直没用起来。
这次买了一个 Saleae 的CY68013的基础版本,终于是跑起来了。 https://whycan.cn/t_2890.html#p23740
但是在解析UART协议时,发现第一个起始点的下降沿无法正确解析,造成数据出错。
在 sigrok 的 bugzilla 发了贴,发现可以设置信号的初始状态。这功能默认是关闭了。
没有好好看文档,所以走了弯路。
https://sigrok.org/bugzilla/show_bug.cgi?id=1418
1。 在配置中允许设置信号的初始状态
2. 在UART协议中设置初始状态
3. 此时可以正确解析
https://sigrok.org/bugzilla/show_bug.cgi?id=1418
他们说就是这样子的,他们的正常,有贴图为证。
必须要有一个下降沿,可以设置信号的初始状态为高来获取下降沿。
但我没找到设置的办法。
页次: 1