C 如何正确初始化覆盆子?
我编写了一个电机控制器,并使用Arch Arm Linux发行版在respberry pi上进行了测试,计算控制信号需要约0.4ms,因此我认为如果使用实时操作系统,我可以做得更好,因此我开始使用ChibiOS,但运行时间约为2.5ms,首先我使用Crossfire交叉编译器,然后切换到linaro,使用linaro时,运行时间稍差,约为2.7ms。有什么问题吗?是否有可能我没有以最佳方式初始化硬件C 如何正确初始化覆盆子?,c,assembly,arm,hardware,cross-compiling,C,Assembly,Arm,Hardware,Cross Compiling,我编写了一个电机控制器,并使用Arch Arm Linux发行版在respberry pi上进行了测试,计算控制信号需要约0.4ms,因此我认为如果使用实时操作系统,我可以做得更好,因此我开始使用ChibiOS,但运行时间约为2.5ms,首先我使用Crossfire交叉编译器,然后切换到linaro,使用linaro时,运行时间稍差,约为2.7ms。有什么问题吗?是否有可能我没有以最佳方式初始化硬件 /* * Stack pointers initialization.
/*
* Stack pointers initialization.
*/
ldr r0, =__ram_end__
/* Undefined */
msr CPSR_c, #MODE_UND | I_BIT | F_BIT
mov sp, r0
ldr r1, =__und_stack_size__
sub r0, r0, r1
/* Abort */
msr CPSR_c, #MODE_ABT | I_BIT | F_BIT
mov sp, r0
ldr r1, =__abt_stack_size__
sub r0, r0, r1
/* FIQ */
msr CPSR_c, #MODE_FIQ | I_BIT | F_BIT
mov sp, r0
ldr r1, =__fiq_stack_size__
sub r0, r0, r1
/* IRQ */
msr CPSR_c, #MODE_IRQ | I_BIT | F_BIT
mov sp, r0
ldr r1, =__irq_stack_size__
sub r0, r0, r1
/* Supervisor */
msr CPSR_c, #MODE_SVC | I_BIT | F_BIT
mov sp, r0
ldr r1, =__svc_stack_size__
sub r0, r0, r1
/* System */
msr CPSR_c, #MODE_SYS | I_BIT | F_BIT
mov sp, r0
mov r0,#0x8000
mov r1,#0x0000
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
;@ enable fpu
mrc p15, 0, r0, c1, c0, 2
orr r0,r0,#0x300000 ;@ single precision
orr r0,r0,#0xC00000 ;@ double precision
mcr p15, 0, r0, c1, c0, 2
mov r0,#0x40000000
fmxr fpexc,r0
mov r0, #0
ldr r1, =_bss_start
ldr r2, =_bss_end
和内存设置:
__und_stack_size__ = 0x0004;
__abt_stack_size__ = 0x0004;
__fiq_stack_size__ = 0x0010;
__irq_stack_size__ = 0x0080;
__svc_stack_size__ = 0x0004;
__sys_stack_size__ = 0x0400;
__stacks_total_size__ = __und_stack_size__ + __abt_stack_size__ + __fiq_stack_size__ + __irq_stack_size__ + __svc_stack_size__ + __sys_stack_size__;
MEMORY
{
ram : org = 0x8000, len = 0x06000000 - 0x20
}
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
SECTIONS
{
. = 0;
.text : ALIGN(16) SUBALIGN(16)
{
_text = .;
KEEP(*(vectors))
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
*(.ctors)
*(.dtors)
} > ram
.ARM.extab : {*(.ARM.extab* .gnu.linkonce.armextab.*)} > ram
__exidx_start = .;
.ARM.exidx : {*(.ARM.exidx* .gnu.linkonce.armexidx.*)} > ram
__exidx_end = .;
.eh_frame_hdr : {*(.eh_frame_hdr)}
.eh_frame : ONLY_IF_RO {*(.eh_frame)}
. = ALIGN(4);
_etext = .;
_textdata = _etext;
.data :
{
_data = .;
*(.data)
. = ALIGN(4);
*(.data.*)
. = ALIGN(4);
*(.ramtext)
. = ALIGN(4);
_edata = .;
} > ram
.bss :
{
_bss_start = .;
*(.bss)
. = ALIGN(4);
*(.bss.*)
. = ALIGN(4);
*(COMMON)
. = ALIGN(4);
_bss_end = .;
} > ram
}
PROVIDE(end = .);
_end = .;
__heap_base__ = _end;
__heap_end__ = __ram_end__ - __stacks_total_size__;
__main_thread_stack_base__ = __ram_end__ - __stacks_total_size__;
我在哪里犯了错误?很久以前(是的,这意味着在上一个千年中),我使用旧的(电流稍大的补丁)通过连接到并行端口数据线的继电器控制步进电机。请注意,该驱动程序与当前的
pcspkr
驱动程序不同(它只写入实际的扬声器,而不写入并行端口);pcsp的支持并行输出的部分从未移植到2.6音频架构
诀窍在于,驱动程序可以注册一个(高优先级,如果需要)中断例程,该例程执行实际的设备寄存器/IO端口写入以更改线路状态。因此,您只需将采样率ioctl()
发送给驱动程序,然后在内存中异步写入创建的“斜坡”(数据信号的上升/下降到/从某个速度或执行多个步骤)-驱动程序随后将为您假脱机,而不需要额外的计时/调度敏感代码
最后,您在并行端口数据引脚上获得了一个8位数字信号,计时精度达到定时器中断允许的最高值。有足够的线来驱动步进机;如果你想让它转一个给定的步骤数,你必须:
- 创建一个“渐变”,将其从静止加速到最快
- 创建一个“矩形波”以保持其旋转
- 创建一个“缓降”以使其再次减速
您的计时精度,再次,是由您的定时器中断的速率和抖动限制。RaspPI能够运行比i386更高的定时器中断速率。我很确定1ms对于这种方法来说不是一个挑战(1995年不是)。如前所述,该方法取决于预处理信号的能力。“计算控制信号”,这是一种算法吗?你为什么不尝试改进一下呢?我不想使用Linux,我只是想知道如何正确初始化RPI硬件。初始化SoC不仅仅是设置ARM核心特权状态。无MMU的ARM7/9和Cortex-M与ARM11/Cortex-a之间有很大的区别。这就是为什么使用已经完成的现有操作系统是个好主意;应该有对树莓的ChibiOS支持,-我还没有测试过。