页次: 1
你这个不知道能不能跑起来,我给你个我裸机的给你参考下吧。我这个是keil版本的,想要进入IRQ模式还是需要设置 cpsr寄存器的。
AREA WB_INIT, CODE, READONLY
USR_MODE EQU 0x10
FIQ_MODE EQU 0x11
IRQ_MODE EQU 0x12
SVC_MODE EQU 0x13
ABT_MODE EQU 0x17
UDF_MODE EQU 0x1B
SYS_MODE EQU 0x1F
I_BIT EQU 0x80
F_BIT EQU 0x40
IRQ_RAMStack EQU 0x81FA0000
DRAM_Limit EQU 0x81F00000 ;DDR栈顶
RAM_Limit EQU 0x4000 ;内存大小 32k
UND_Stack EQU RAM_Limit - 128
Abort_Stack EQU RAM_Limit - 256
IRQ_Stack EQU RAM_Limit - 512
FIQ_Stack EQU RAM_Limit - 768
SVC_Stack EQU RAM_Limit - 1024
USR_Stack EQU RAM_Limit - 2048
ENTRY
; EXPORT Reset_Go
; EXPORT Vector_Table
IMPORT ||Load$$ER_IROM1$$Length||
IMPORT ||Image$$RW_RAM1$$RW$$Length||
; 链接器产生代码链接运行位置
_start
; /* Boot head information for BROM */
DCD 0xea000016
DCB 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
DCD 0, ||Load$$ER_IROM1$$Length||
; DCD 0, __bootloader_size
DCB 'S', 'P', 'L', 2
DCD 0, 0
DCD 0, 0, 0, 0, 0, 0, 0, 0
DCD 0, 0, 0, 0, 0, 0, 0, 0 ;/* 0x40 - boot params, 0x58 - fel boot type, 0x5c - dram size */
Vector_Table
B Reset_Go
LDR PC, Undefined_Addr
LDR PC, SWI_Addr
LDR PC, Prefetch_Addr
LDR PC, Abort_Addr
DCD 0x0
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
Reset_Addr DCD Reset_Go
Undefined_Addr DCD Undefined_Handler
SWI_Addr DCD SWI_Handler1
Prefetch_Addr DCD Prefetch_Handler
Abort_Addr DCD Abort_Handler
DCD 0
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undefined_Handler
B Undefined_Handler
SWI_Handler1
B SWI_Handler1
Prefetch_Handler
B Prefetch_Handler
Abort_Handler
B Abort_Handler
IMPORT arm32_do_irq
PRESERVE8
IRQ_Handler
ldr sp,=IRQ_RAMStack
sub sp, sp, #72
stmia sp, {r0 - r12}
add r8, sp, #60
stmdb r8, {sp, lr}^
str lr, [r8, #0]
mrs r6, spsr
str r6, [r8, #4]
str r0, [r8, #8]
mov r0, sp
bl arm32_do_irq
ldmia sp, {r0 - lr}^
mov r0, r0
ldr lr, [sp, #60]
add sp, sp, #72
subs pc, lr, #4
FIQ_Handler
B FIQ_Handler
EXPORT __CodeAddr__
EXPORT __RamSize__
; 引入链接器产生符号,以确定代码运行位置,编译生成的大小
IMPORT ||Image$$ER_IROM1$$Base||
IMPORT ||Image$$RW_RAM1$$ZI$$Base||
IMPORT ||Image$$RW_RAM1$$ZI$$Length||
IMPORT ||Image$$RW_RAM1$$RW$$Length||
IMPORT ||Image$$ER_IROM1$$Length||
IMPORT ||Image$$ER_IROM2$$Length||
; IMPORT ||Image$$ER_IROM2$$Length||
; 链接器产生代码链接运行位置
__CodeAddr__ DCD ||Image$$ER_IROM1$$Base||
__CodeSize__ DCD ||Image$$ER_IROM1$$Length|| + ||Image$$ER_IROM2$$Length||
__RamSize__ DCD ||Image$$ER_IROM1$$Length|| + ||Image$$ER_IROM2$$Length|| + ||Image$$RW_RAM1$$RW$$Length||
__BssStart__ DCD ||Image$$RW_RAM1$$ZI$$Base||
__BssLenth__ DCD ||Image$$RW_RAM1$$ZI$$Length||
Reset_Go
;/* Save boot params to 0x00000040 */
ldr r0, __CodeAddr__
ldr r1,__CodeSize__
ldr r2,__RamSize__
ldr r3,__RamSize__
ldr r0, =0x01C20C04 ;清除定时器中断
ldr r1, = 0x01
str r1,[r0]
ldr r0, =0x01c20410 ;屏蔽所有中断
ldr r1, = 0xffffffff
str r1,[r0]
ldr r0, =0x00000040
str sp, [r0, #0]
str lr, [r0, #4]
mrs lr, cpsr
str lr, [r0, #8]
mrc p15, 0, lr, c1, c0, 0
str lr, [r0, #12]
mrc p15, 0, lr, c1, c0, 0
str lr, [r0, #16]
; /* Check boot type just for fel */
mov r0, #0x0
ldr r1, [r0, #8]
ldr r2, =0x4c45462e
cmp r1, r2
bne lab1
; ldr r1, =0x1
; str r1, [r0, #0x58]
lab1 nop
; /* Enter svc mode and mask interrupts */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr CPSR_cxsf, r0
; /* Set vector to the low address */
mrc p15, 0, r0, c1, c0, 0
bic r0, #(1<<13)
mcr p15, 0, r0, c1, c0, 0
; /* Copy vector to the correct address */
adr r0, Vector_Table
mrc p15, 0, r2, c1, c0, 0
ands r2, r2, #(1 << 13)
ldreq r1, =0x00000000
ldrne r1, =0xffff0000
; mcr p15, 0, r2, c1, c0, 0
ldmia r0!, {r2-r8, r10}
stmia r1!, {r2-r8, r10}
ldmia r0!, {r2-r8, r10}
stmia r1!, {r2-r8, r10}
IMPORT sys_clock_init
IMPORT sys_dram_init
IMPORT sys_spi_flash_init
IMPORT sys_spi_flash_read
IMPORT sys_spi_flash_exit
IMPORT system_register_time_int
IMPORT memcpy
IMPORT memset
IMPORT MMU_Init
PRESERVE8
; /* Boot speed up, leave slower sram */
adr r0, _start
ldr r1, =_start
cmp r0, r1
beq _speedup
bl sys_clock_init
bl sys_dram_init
bl sys_spi_flash_init
; bl MMU_Init
ldr r0,=0x00
ldr r1,__CodeAddr__
ldr r2,__RamSize__
bl sys_spi_flash_read
ldr r0, =_speedup
ldr r1, =_start
sub r0, r0, r1
ldr r1, __CodeAddr__
add r0, r0, r1
ldr r0, =0x01c20810
ldr r1, = 0x0f
str r1,[r0]
_speedup
nop
MSR CPSR_c, #UDF_MODE :OR: I_BIT :OR: F_BIT
LDR SP, =UND_Stack + DRAM_Limit
MSR CPSR_c, #ABT_MODE :OR: I_BIT :OR: F_BIT
LDR SP, =Abort_Stack + DRAM_Limit
MSR CPSR_c, #IRQ_MODE :OR: I_BIT :OR: F_BIT
LDR SP, =IRQ_Stack + DRAM_Limit
MSR CPSR_c, #FIQ_MODE :OR: I_BIT :OR: F_BIT
LDR SP, =FIQ_Stack + DRAM_Limit
MSR CPSR_c, #SYS_MODE :OR: I_BIT :OR: F_BIT
LDR SP, =USR_Stack + DRAM_Limit
MSR CPSR_c, #SVC_MODE :OR: I_BIT :OR: F_BIT
LDR SP, =SVC_Stack + DRAM_Limit
MRS r1, CPSR
; BIC r1, #0x1f
; ORR r1, #0x7f;进入IRQ模式
AND r1, #0x7f ;允许IRQ中断
MSR CPSR_c,r1
IMPORT __main
adr r0, _start
ldr r1, =_start
cmp r0, r1
bne _NoDdr
_NoDdr
LDR R0, =__main
BX R0
end
其實原本的b irq_handler的意思就是跳轉, 但是改成如下, 還是無法挑轉到irq_handler
_vector: b reset b . b . b . b . b . ldr pc, irq_handler ldr pc, irq_handler irq_handler: str r1, [r0, #(PE + PORT_DATA)] subs pc, lr, #4
我知道你直接写b irq_handler 也可以,但这个前提是你的irq_handler是在32MB范围内 因为b只能跳转32M范围,所以我觉得用LDR更好点而已。但是FIRQ中断是在IRQ的下一个地址嘛,你不是没写嘛所以我叫你加上。 至于你加上也不行,那是不是你并没有进入FIRQ中断呢?
感觉应该是跑起来了,但是显示屏上显示的又贼慢。
gst-launch-1.0 filesrc location=bad_apple.mp4 ! qtdemux ! h264parse ! omxh264d
ec ! autovideoconvert ! fbdevsink
[ 31.842570] vcc3v0: disabling
[ 31.845580] vcc5v0: disabling
Setting pipeline to PAUSED ...
debug : cedarc <AwOmxComponentInit:26>:OMXCORE: aw_omx_component_init 126000
debug : omx_vdec <__AwOmxVdecInit:1059>:++++++++++++++++++++++omx begin++++++++++++++++++
debug : omx_vdec <__AwOmxVdecInit:1060>:name = OMX.allwinner.video.decoder.avc
debug : omx_vdec_aw <OmxDecoderCreate:962>:kay: ** 0.
debug : cedarc <CdcMessageQueueCreate:47>:nMessageSize = 20
debug : cedarc <AwOmxComponentSetCallbacks:310>:OMXCORE: aw_omx_component_set_callbacks 126000, b6695508 , 9a8b0
debug : omx_vdec <__AwOmxVdecSetCallbacks:1812>:===== vdec set callbacks
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
Pipeline is PREROLLING ...
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
debug : omx_vdec <AwOmxVdecPortSetDefinitioin:192>:port:<<<<<<<<in,nBufferCountActual = 2, mBufferCntActual = 2
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
debug : omx_vdec <AwOmxVdecPortSetDefinitioin:192>:port:<<<<<<<<in,nBufferCountActual = 2, mBufferCntActual = 2
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf-------format=7f000002
hxf2-------format=3
error : omx_vdec <AwOmxVdecPortGetFormat:289>:erro: pParamData->nIndex > m_sPortFormatType.nIndex
hxf__src/omx_vdec_port.c AwOmxVdecPortGetFormat 290---------------
hxf default format=7f000002__src/omx_vdec_port.c AwOmxVdecPortGetFormat 294---------------
debug : omx_vdec <controlSetState:359>:current state:OMX_StateLoaded, target state:OMX_StateIdle
debug : omx_vdec <doStateWaitforResources2Idle:563>:bEnabled[1],[1],bPopulated[0],[0]
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1693>:kay: __AwOmxVdecAllocateBuffer
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1713>:kay: __AwOmxVdecAllocateBuffer 2
debug : omx_vdec_aw <__liAllocatePortBuffer:889>:kay: *** 0.
debug : omx_vdec_aw <__liAllocatePortBuffer:901>:kay: malloc
debug : omx_vdec_aw <__liAllocatePortBuffer:903>:kay: malloc2
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1715>:kay: __AwOmxVdecAllocateBuffer 3
debug : omx_vdec <AwOmxVdecPortPopBuffer:396>:*******port pop buffer:<<<<<<<<in
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1693>:kay: __AwOmxVdecAllocateBuffer
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1713>:kay: __AwOmxVdecAllocateBuffer 2
debug : omx_vdec_aw <__liAllocatePortBuffer:889>:kay: *** 0.
debug : omx_vdec_aw <__liAllocatePortBuffer:901>:kay: malloc
debug : omx_vdec_aw <__liAllocatePortBuffer:903>:kay: malloc2
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1715>:kay: __AwOmxVdecAllocateBuffer 3
debug : omx_vdec <AwOmxVdecPortPopBuffer:396>:*******port pop buffer:<<<<<<<<in
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1693>:kay: __AwOmxVdecAllocateBuffer
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1713>:kay: __AwOmxVdecAllocateBuffer 2
debug : omx_vdec_aw <__liAllocatePortBuffer:889>:kay: *** 0.
debug : omx_vdec_aw <__liAllocatePortBuffer:901>:kay: malloc
debug : omx_vdec_aw <__liAllocatePortBuffer:903>:kay: malloc2
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1715>:kay: __AwOmxVdecAllocateBuffer 3
debug : omx_vdec <AwOmxVdecPortPopBuffer:396>:*******port pop buffer:>>>>>>>out
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1693>:kay: __AwOmxVdecAllocateBuffer
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1713>:kay: __AwOmxVdecAllocateBuffer 2
debug : omx_vdec_aw <__liAllocatePortBuffer:889>:kay: *** 0.
debug : omx_vdec_aw <__liAllocatePortBuffer:901>:kay: malloc
debug : omx_vdec_aw <__liAllocatePortBuffer:903>:kay: malloc2
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1715>:kay: __AwOmxVdecAllocateBuffer 3
debug : omx_vdec <AwOmxVdecPortPopBuffer:396>:*******port pop buffer:>>>>>>>out
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1693>:kay: __AwOmxVdecAllocateBuffer
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1713>:kay: __AwOmxVdecAllocateBuffer 2
debug : omx_vdec_aw <__liAllocatePortBuffer:889>:kay: *** 0.
debug : omx_vdec_aw <__liAllocatePortBuffer:901>:kay: malloc
debug : omx_vdec_aw <__liAllocatePortBuffer:903>:kay: malloc2
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1715>:kay: __AwOmxVdecAllocateBuffer 3
debug : omx_vdec <AwOmxVdecPortPopBuffer:396>:*******port pop buffer:>>>>>>>out
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1693>:kay: __AwOmxVdecAllocateBuffer
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1713>:kay: __AwOmxVdecAllocateBuffer 2
debug : omx_vdec_aw <__liAllocatePortBuffer:889>:kay: *** 0.
debug : omx_vdec_aw <__liAllocatePortBuffer:901>:kay: malloc
debug : omx_vdec_aw <__liAllocatePortBuffer:903>:kay: malloc2
debug : omx_vdec <__AwOmxVdecAllocateBuffer:1715>:kay: __AwOmxVdecAllocateBuffer 3
debug : omx_vdec <AwOmxVdecPortPopBuffer:396>:*******port pop buffer:>>>>>>>out
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
debug : omx_vdec <doStateWaitforResources2Idle:563>:bEnabled[1],[1],bPopulated[1],[1]
debug : omx_vdec <controlSetState:380>:Transit current state:OMX_StateLoaded --> target state:OMX_StateIdle --OK!
debug : omx_vdec <controlSetState:359>:current state:OMX_StateIdle, target state:OMX_StateExecuting
debug : omx_vdec <controlSetState:380>:Transit current state:OMX_StateIdle --> target state:OMX_StateExecuting --OK!
debug : omx_vdec_aw <liDealWithInitData:156>:fatal error! pInBufHdr is NULL, check code!
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
debug : omx_vdec_aw <liDealWithInitData:175>:++++++++++++++++pCtx->mCodecSpecificDataLen[0]
debug : omx_vdec_aw <__liPrepare:464>:decoder prepare
warning: cedarc <AddVDPlugin:1538>: 1117 get local path: /usr/lib/
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawavs.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawavs.so
warning: cedarc <VDecoderRegister:127>: register codec: '117:avs' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawh264.so
hxf__src/omx_vdec_aw_decoder_linux.c __liGetFormat 875---------------
hxf-------format=7f000002
hxf2-------format=3
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawh264.so
warning: cedarc <VDecoderRegister:127>: register codec: '115:h264' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawh265.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawh265.so
warning: cedarc <VDecoderRegister:127>: register codec: '116:h265' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmjpeg.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmjpeg.so
warning: cedarc <VDecoderRegister:127>: register codec: '101:mjpeg' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmjpegplus.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmjpegplus.so
warning: cedarc <VDecoderRegister:127>: register codec: '101:mjpegplus' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmpeg2.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmpeg2.so
warning: cedarc <VDecoderRegister:127>: register codec: '102:mpeg2' success.
warning: cedarc <VDecoderRegister:127>: register codec: '103:mpeg2' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmpeg4base.so
warning: cedarc <AddVDPluginSingle:1498>: Invalid plugin, CedarPluginVDInit not found.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmpeg4dx.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmpeg4dx.so
warning: cedarc <VDecoderRegister:127>: register codec: '105:mpeg4dx' success.
warning: cedarc <VDecoderRegister:127>: register codec: '106:mpeg4dx' success.
warning: cedarc <VDecoderRegister:127>: register codec: '107:mpeg4dx' success.
warning: cedarc <VDecoderRegister:127>: register codec: '10e:mpeg4dx' success.
warning: cedarc <VDecoderRegister:127>: register codec: '10f:mpeg4dx' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmpeg4h263.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmpeg4h263.so
warning: cedarc <VDecoderRegister:127>: register codec: '104:mpeg4H263' success.
warning: cedarc <VDecoderRegister:127>: register codec: '10b:mpeg4H263' success.
warning: cedarc <VDecoderRegister:127>: register codec: '10d:mpeg4H263' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmpeg4normal.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmpeg4normal.so
warning: cedarc <VDecoderRegister:127>: register codec: '10a:mpeg4Normal' success.
warning: cedarc <VDecoderRegister:127>: register codec: '10c:mpeg4Normal' success.
warning: cedarc <VDecoderRegister:127>: register codec: '108:mpeg4Normal' success.
warning: cedarc <VDecoderRegister:127>: register codec: '109:mpeg4Normal' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawmpeg4vp6.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawmpeg4vp6.so
warning: cedarc <VDecoderRegister:127>: register codec: '111:Mpeg4Vp6' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawvp8.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawvp8.so
warning: cedarc <VDecoderRegister:127>: register codec: '112:vp8' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawvp9Hw.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawvp9Hw.so
warning: cedarc <VDecoderRegister:127>: register codec: '113:Vp9Hw' success.
warning: cedarc <AddVDPlugin:1548>: 1117 load so: /usr/lib/libawwmv3.so
debug : cedarc <AddVDPluginSingle:1501>: vdecoder open lib: /usr/lib/libawwmv3.so
warning: cedarc <VDecoderRegister:127>: register codec: '110:vc1' success.
debug : cedarc <LogVersionInfo:40>:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Cedar Codec <<<<<<<<<<<<<<<<<<<<<<<<<<<<
tag : CedarC-v1.1.9
branch: master
commit: 1951abe1456450ea48bfd446e801861a1354e93c
date : Wed May 30 18:59:36 2018 +0800
author: jenkins8080
patch :
----------------------------------------------------------------------
debug : cedarc <CreateVideoDecoder:215>:CreateVideoDecoder ****
debug : ionAlloc <__GetIonMemOpsS:985>:*** get __GetIonMemOpsS ***
debug : ionAlloc <ion_alloc_open:134>:begin ion_alloc_open
debug : cedarc <VeSetSpeed:1559>: *** set ve freq to 300 Mhz ***
debug : cedarc <VeInitialize:1198>: ve init ok
debug : ionAlloc <ion_alloc_open:175>:** phy offset = 40000000
debug : cedarc <VeRelease:1253>: ve release ok
从后面输出的显示来看应该是一直在解码的样子。这里fb显示报的警告说大量缓冲区的数据被丢弃了。
WARNING: from element /GstPipeline:pipeline0/GstFBDEVSink:fbdevsink0: A lot of buffers are being dropped.
Additional debug info:
../libs/gst/base/gstbasesink.c(3005): gst_base_sink_is_too_late (): /GstPipeline:pipeline0/GstFBDEVSink:fbdevsink0:
There may be a timestamping problem, or this computer is too slow.
hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 724---------------
*** picture info: w(512),h(384),offset,t(0),b(384),l(0),r(512)hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 740---------------
hxf__pixel_format.c ConvertPixelFormat 766---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 724---------------
*** picture info: w(512),h(384),offset,t(0),b(384),l(0),r(512)hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 740---------------
hxf__pixel_format.c ConvertPixelFormat 766---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 724---------------
*** picture info: w(512),h(384),offset,t(0),b(384),l(0),r(512)hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 740---------------
hxf__pixel_format.c ConvertPixelFormat 766---------------
hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 724---------------
*** picture info: w(512),h(384),offset,t(0),b(384),l(0),r(512)hxf__src/omx_vdec_aw_decoder_linux.c __liDrain 740---------------
其实嘛在哇酷网右上角搜索一下就会发现你的问题可以找到答案了。
https://whycan.com/t_5426.html
gc0308。在哪买的
某宝了解一下,7.5哟。
https://m.tb.cn/h.4muxbBp?sm=e4fd1b
@Kevincoooool
你好,以及哇酷的站长您好,我是帖子中的店铺管理者,由于我的侵权,甚至是无知,我倒卖了开源的作品,是我不对,只是为了搞点小钱,就侵犯了,甚至不顾及了劳动成果,是我的不对,别人购买了这个产品,我也是再说,这个不是我的原创,是网络的以为大佬做的,我并没有声称是自己的劳动成果,在此所有的产品,我已经下架了,来这里给大家以及原创道个歉!
你这个1积分是如何下载到东西的,没有道理,既然不是晕哥的忠实粉丝。其实嘛可以自己下载改一改啥的,如果实在没这技术,店铺表明出处加上个如有侵权请联系,小本生意挣点外快不容易。再给吹嘘一波楼主,说不定楼主一开心还给你下个百八十单的=。=
Can someone please post the first file(sunxi-tools-win32-support_f1c100s_32M.7z), so I can download it? Thank you.
You can recharge your account and then you can download it Ha Ha.
This is a tutorial to become a VIP.
楼主,请问歌曲名左右滚动显示,是lvgl控件内置具备的特性吗?
好像是有这么个功能的我之前看过lvgl的帮助文档label里面有个是这样的。是左右滚还是循环滚应该是可以设置模式的。
void lv_ex_label_text(void)
{
lv_obj_t * label2 = lv_label_create(lv_scr_act(), NULL);
lv_label_set_long_mode(label2, LV_LABEL_LONG_SROLL_CIRC); /*Circular scroll*/
lv_obj_set_width(label2, 150);
lv_label_set_text(label2, "It is a circularly scrolling text. ");
lv_obj_align(label2, NULL, LV_ALIGN_CENTER, 0, 30);
}
https://docs.ai-thinker.com/tg
说是支持二次开发,集成了Linux开发环境。不知道有没有优先吃瓜大佬。
我觉得这个应该是imgbtn默认style的问题,估计是里面的label默认就是居中显示的,所以你设置的align无效。这个有点像你把一个容器设置这个
lv_cont_set_layout(h, LV_LAYOUT_PRETTY_MID);布局之后,你在里面使用align去设置他的子代都是无效的。具体的我还没去研究过,我一般是如下操作去设置的。
tv = lv_tabview_create(lv_scr_act(), NULL);
LV_IMG_DECLARE(imgbtn_green);
LV_IMG_DECLARE(imgbtn_blue);
lv_obj_t * imgbtn1 = lv_imgbtn_create(tv, NULL);
lv_imgbtn_set_src(imgbtn1, LV_BTN_STATE_RELEASED, &imgbtn_green);
lv_imgbtn_set_src(imgbtn1, LV_BTN_STATE_PRESSED, &imgbtn_green);
lv_imgbtn_set_src(imgbtn1, LV_BTN_STATE_CHECKED_RELEASED, &imgbtn_blue);
lv_imgbtn_set_src(imgbtn1, LV_BTN_STATE_CHECKED_PRESSED, &imgbtn_blue);
lv_obj_t * label = lv_label_create(tv, NULL);
lv_label_set_text(label, "12");
lv_obj_align(label, imgbtn1, LV_ALIGN_IN_LEFT_MID, 10, 0);
lv_imgbtn_set_checkable(imgbtn1, true);
从lvgl的教程了看到有现成的keyboard输入,但是发现有很多不好使的地方,一个是可以点击关闭就把键盘给关闭了。第二个是没有提供给用户处理关闭等事件的接口。此例子实现点击输入框显示键盘输入,点击输入框外关闭键盘。实验效果如下:
输入部分代码如下:希望帮到有需求的人。
static void ta_event_cb(lv_obj_t * ta, lv_event_t event);
static lv_obj_t * kb = NULL;
static void kb_event_cb(lv_obj_t * p_key, lv_event_t event)
{
if (event == LV_EVENT_CANCEL)
{
printf("CLOSE\n"); //自己处理关闭事件
return;
}
else if (event == LV_EVENT_APPLY)
{
printf("OK\n"); //OK事件
return;
}
lv_keyboard_def_event_cb(p_key, event); //这里回调原来的处理函数
}
static void ta_event_cb(lv_obj_t * ta, lv_event_t event)
{
if (event == LV_EVENT_VALUE_CHANGED) {
const char * txt = lv_textarea_get_text(ta);
if (txt[0] >= '0' && txt[0] <= '9' &&
txt[1] >= '0' && txt[1] <= '9' &&
txt[2] != ':')
{
lv_textarea_set_cursor_pos(ta, 2);
lv_textarea_add_char(ta, ':');
}
}
else if (event == LV_EVENT_FOCUSED)
{
if (kb != NULL)return;
kb = lv_keyboard_create(t2, NULL);
lv_obj_set_size(kb, 400, 200);
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUM);
lv_keyboard_set_textarea(kb, ta);
lv_keyboard_set_cursor_manage(kb, true);
lv_obj_set_event_cb(kb, kb_event_cb); //设置自己处理事件,避免kb自己点击就关闭了输入
}
else if (event == LV_EVENT_DEFOCUSED)
{
if (kb != NULL)
{
lv_obj_del(kb);
kb = NULL;
}
}
}
static parameter_creat(lv_obj_t * parent)
{
lv_page_set_scrl_layout(parent, LV_LAYOUT_PRETTY_TOP);
lv_obj_t * ta = lv_textarea_create(parent, NULL);
lv_obj_set_event_cb(ta, ta_event_cb);
lv_textarea_set_accepted_chars(ta, "0123456789:");
lv_textarea_set_max_length(ta, 5);
lv_textarea_set_one_line(ta, true);
lv_textarea_set_text(ta, "");
}
通过上面公式拆解,可以得到rgb和yuv的直接公式如下:
r = (y + (359 * v)) >> 8; = y/256 + (359*(V-128))/256 = y + (359*V - 45952)/256 = y+ 1.40234375*v - 179.5
g = (y - (88 * u) - (183 * v)) >> 8; =y/256 -(88*(u-128))/256 - (183*(v-128))/256 = y -(88*u-11264)/256 - (183*v-23424)/256=y -0.34375u+44 -0.71484375*v + 91.5 = y-0.34375u-0.71484375*v + 135.5
b = (y + (454 * u)) >> 8; = y/256 + (454*(u-128))/256 = y + (454u-58112)/256 = y + 1.7734375u - 227
统一下就是:
r =y+ 1.40234375*v - 179.5
g =y-0.34375u-0.71484375*v + 135.5
b =y + 1.7734375u - 227
但是和这个公式一配比的话,他这个系数无法变为负数,最后那个常量也无法变为负数了。所以此公式也对应不上呀。
要么就用已知的YUV 和RGB的值套上全志手册的公式解12次一元一次方矩阵?以此得到系数?或者有没有大佬已经有系统跑通了的可以读取下0x01E60950 - 0x01E60980的值给来参考下。
vip888888 说:应用获取摄像头数据参考文件如下, 下载之后另存为.c就行了(因为不支持上传后缀.c的文件所以重命名了而已)。
testApp.gz可以获取jpg图片了,谢谢楼主!
客气客气,好了就行。
应用获取摄像头数据参考文件如下, 下载之后另存为.c就行了(因为不支持上传后缀.c的文件所以重命名了而已)。
testApp.gz
vip888888 说:板子就买的这个了。
工程用的大佬的这个,已经支持了ov2640 https://whycan.com/t_5221.html。
https://whycan.com/files/members/4813/TINY200.jpg请教下在linux中直接获取jpeg的方法,底层的话可以直接改驱动输出jpeg。这个底层输出jpeg我大概改的有点点输出,图片看起来有点错位。
https://whycan.com/files/members/4813/camera.jpg
我应用上还是按照YUYV的方式初始化摄像头的。以此来获取一帧数据。但是好像不是很好使。
https://whycan.com/files/members/4813/camera1.png
https://whycan.com/files/members/4813/camera2.png请问楼主,改输出jpeg是怎么改的?改初始化寄存器吗?可否参考下
网上一搜就有了,2640手册没有关于jpeg方面的说明,我也就网上搜的然后加到初始化就行了。
各位大佬们好,问题见标,我有一个预研的项目需要使用ESP32-CAM从OV2640获取1600*1200的JPEG数据并通过Wi-Fi(TCP传出)。ESP32使用IDF提供的FreeRTOS,要求传输的帧率达到10FPS。
经过查找,OV2640的UXGA分辨率下最大帧率是15FPS,也就是说在传感器侧是能达到这个速度的。
我做了两个测试:
(1)RTOS启动到app_main()之后,开启一个1s定时器做标定输出,while(1)不停获取图像并仅打印数据长度(也就是不对图像数据做拷贝等操作),获取的速度能达到约11~12FPS。
(2)启动Wi-Fi,通过TCP连接到电脑的网口助手,在TCP连接的状态下,获取数据并使用LWIP的send函数发送裸JPEG数据到PC,帧率只有3FPS左右;将JPEG质量从原来的12(数据量80K/张左右)降低到30(数据量50K/张左右),帧率达到4~5FPS。请问是我哪里的操作导致了数据处理速度下降么?还是ESP32(432MHz)的性能无法达到这个需求?
又或者...有没有哪些可供优化的方法呢?感谢大家~嗷呜!!
就你这里获取15fps来说的话大概你是有66.6ms可以用来传输,这样的话可以保证不丢帧。所以这个问题就是确定你自己的esp32传输速度了。这个芯片我没玩过,但是你可以单独测试传输的速度。我看网上说这个芯片实测的传输速度也就几百K左右,所以按照你80K*3=240KB/s可能也就差不多就这样子。我最近刚测试的ov2640的800x600的jpeg在室内开灯大概是15K一帧的大小。如果没有必须要求1600x1200的话你可以将输出大小设置为800x600这样15k*10fps也就是150KB。这样你的速度就可以达到了。
裸跑F1C100S 使用SPI1时候发现,设置spi1寄存器,再读取发现一直时0,没有设置进去。有朋友遇到过没。
SPI1时钟已经开启:
// SPI1 打开时钟 //
write32( 0x01C20060, (read32(0x01C20060) | (1<<21)) );SPI1寄存器基地址也没错0x01c06000,读取SPI0的寄存器就可以返回数据。
使能时钟后一般要使能时钟复位。200s手册上可以查到 spi1_rst是偏移0x02c0地址寄存器的第21位。
所以你可以在后面加上一句write32( 0x01C20000+0x2c0, (read32(0x01C20000+0x2c0) | (1<<21)) );
然后在延时个1ms。然后再操作寄存器看。
关于乱码的问题,后来用二进制查看得到的jpeg数据,发现当我用mmap的时候把width设置成640的时候可以看到是多填充了一些0数据导致数据错乱,根据ov2640输出jpeg的格式开头是0xff 0xd8 结尾是0xff 0xd9。看数据发现每次输出的循环是1280(yuyv输出每个像素2字节640*2),数据前面的1024个字节是jpeg的数据剩余的都被填充为0。所以直接导致了输出的JPEG错乱。根据此结果我摄像头初始化的时候将widht设置成512(继续用yuyv获取数据512*2=1024)。
ov2640输出jpeg的时候hync和pclk输出都不是固定的,而且一张jpeg的长度本身也不是固定,得看压缩情况,所以如果要保存一张jpeg对于程序来说并不确定是多大,所以利用jpeg结尾符号来做一次数据处理,如下图,就用此板经过测试大概计算一次15K的JPEG大概耗时3ms,写入耗时1.5ms左右(sd卡)。
经过修改测试,得出结论在1600x1200的情况下输出jpeg是15fps。保存存储完全没问题,在800x600的情况下测试输出jpeg的速度达到了45fps。存储速度和读取都没问题。
示波器实测800x600的vync输出速度
此速度下保存的jpeg如下,也完全ok。直接获取数据存储。
至此完成 linux下获取ov2640的jpeg并存储。
openepo 说:我在 tiny200 R3 上实验的结果如下:
1,编译 aodzip 大大 的 https://github.com/aodzip/buildroot-tiny200
2,同时按住 boot / rst, 然后先放开rst, 再放开 boot 键。 然后运行 fel-uboot.sh,注意sunxi-fel的路径和版本, 我是参照脚本手动输入命令的。 正常没有出错提示,tiny200 R3 会内存运行进入 u-boot 模式
3,进入 u-boot 之后, 在主机端运行 dfu-nand-all.sh, 此时会提示等待 dfu 设备
4,在 u-boot 运行 run dfu_boot,此时会开始 dfu 下载。速度还是挺慢的, 我还没刷完,不知道最终结果如何,看上去应该没问题。在第2步运行fel-uboot.sh后出现ERROR: Allwinner USB FEL device not found!
我还尝试过用TF卡启动到U-BOOT,在主机执行dfu-nand-all.sh,再在让开发板执行run dfu_boot,但是没有任何反应
感觉你这提示是usb fel设备没有找到呀?是不是设备没有进入fel模式?正常情况下好像如果进入fel模式windows下的话会有一个设备出来,虚拟机下应该也会有个usb设备之类的吧。
就是指定下交叉编译的工具就行了。具体可能要设置一些配置,我这有个编译qt4.8.7的例子你可以参考下。
https://whycan.com/t_5312.html
阿黄 说:vip888888 说:感谢提醒,确实我后来在他那个image里面的配置文件[[set_partition.es里找到了这个输出,后来我搜索到生成此文件的命令。在project/image/configs/i2m/script_nand.mk中。里面用了echo -e参数。sh脚本把-e 直接当参数写入了配置文件。
对于我现在用的ubuntu 18.04来说 用“sh”执行是调用“/bin/sh”作为执行器,而采用“./”执行是调用申明的“/bin/bash”,而“sh”不支持“echo -e”,所以把“-e”作为内容输出。所以导致配置文件多了个-e选项。
有开发资料可以分享一下吗?
410791550@qq.com 求个sdk学习一下
回头有空我上传一下。
真想全部要这些采样数据就不能直接I/O中断处理,可采用电路移入RAM中,MCU需要数据时DMA进入再使用,可参考示波器原理,那采样率都是几百M或者G。
这种得用啥FPGA来做才行吧?有没有那种就是一些小MCU。比如STM32F4呀F103之类的。这些ram基本都是没有多大的128或者256K的样子了。像这种MCU去读取这个100ksps(假设24bit adc)那么一秒钟ram就得消耗100*3k=300k的RAM了。这应该挺难用了。我看淘宝有人搞出来卖也不知都真假。
https://item.taobao.com/item.htm?spm=a230r.1.14.18.773d2671XVWypm&id=557687584365&ns=1&abbucket=8#detail
板子就买的这个了。
工程用的大佬的这个,已经支持了ov2640 https://whycan.com/t_5221.html。
请教下在linux中直接获取jpeg的方法,底层的话可以直接改驱动输出jpeg。这个底层输出jpeg我大概改的有点点输出,图片看起来有点错位。
我应用上还是按照YUYV的方式初始化摄像头的。以此来获取一帧数据。但是好像不是很好使。
看你的输出log提示应该是你那个的命令参数-e 没有吧?是执行了这个命令"-e ubi create rootfs 0xA00000" ssd的工程应该是读取images下面的配置文件执行里面的命令参数来更新的,你可以在image用grep看能不能搜索到上面那条命令。
感谢提醒,确实我后来在他那个image里面的配置文件[[set_partition.es里找到了这个输出,后来我搜索到生成此文件的命令。在project/image/configs/i2m/script_nand.mk中。里面用了echo -e参数。sh脚本把-e 直接当参数写入了配置文件。
对于我现在用的ubuntu 18.04来说 用“sh”执行是调用“/bin/sh”作为执行器,而采用“./”执行是调用申明的“/bin/bash”,而“sh”不支持“echo -e”,所以把“-e”作为内容输出。所以导致配置文件多了个-e选项。
问题来源是我在18.04下编译(直接用给的脚本编译的) SSD202D(卖家给的SDK)的工程的时候,编译出来的结果无法通过boot网络升级到nand,部分log如下:
>> saveenv
Saving Environment to NAND...
Erasing NAND...
Erasing at 0x440000 -- 100% complete.
Writing to NAND... OK
>> nand erase.part UBI
NAND erase.part: device 0 offset 0xf20000, size 0x70e0000
Erasing at 0x7fe0000 -- 100% complete.
Time:1313531 us, speed:90106 KB/s
OK
>> ubi part UBI
UBI: parsing mtd_dev string 'mtd=11'
UBI: attaching mtd2 to ubi0
UBI: scanning is finished
UBI: empty MTD device detected
UBI: attached mtd2 (name "mtd=11", size 112 MiB) to ubi0
UBI: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
UBI: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
UBI: VID header offset: 2048 (aligned 2048), data offset: 4096
UBI: good PEBs: 903, bad PEBs: 0, corrupted PEBs: 0
UBI: user volume: 0, internal volumes: 1, max. volumes count: 128
UBI: max/mean erase counter: 1/0, WL threshold: 4096, image sequence number: 0
UBI: available PEBs: 879, total reserved PEBs: 24, PEBs reserved for bad PEB handling: 20
>> -e ubi create rootfs 0xA00000
Unknown command '-e' - try 'help'
estar - script via network
Usage:
estar
estar - script via network
请求支援:
MIPI (Mobile Industry Processor Interface)是2003年由ARM, Nokia, ST ,TI等公司成立的一个联盟,目的是把手机内部的接口如摄像头、显示屏接口、射频/基带接口等标准化,从而减少手机设计的复杂程度和增加设计灵活性。MIPI联盟下面有不同的WorkGroup,分别定义了一系列的手机内部接口标准,比如摄像头接口CSI、显示接口DSI、射频接口DigRF、麦克风/喇叭接口SLIMbus等。统一接口标准的好处是手机厂商根据需要可以从市面上灵活选择不同的芯片和模组,更改设计和功能时更加快捷方便。
从如上图来说CSI只是 MIPI的一个WorkGroup?
DVP(Digital Video Port) 是传统的sensor输出接口,采用并行输出方式,d数据位宽有8bit、10bit、12bit、16bit,是CMOS电平信号(重点是非差分信号),PCLK最大速率为96MHz。
那么问题就来了,摄像头有DVP的和MIPI的指的到底是啥?CSI是MIPI类的呢还是DVP类的?还是说此CSI非彼CSI?
f1c100s上写的是有个CSI接口那这种是属于DVP类摄像头接口吗?我看荔枝派上的原理图来说,看起来就像是DVP类的接口呀。那这个CSI和MIPI里面指的那个CSI有何区别的吗?按照这个说法来说DVP的摄像头一般都是小于等于500W。所以想整个800W以上像素的那是咋个整法?
https://whycan.com/files/members/4270/3.png
这是怎么回事,用别人配置好的make 不了
好像是你去勾选了那个buildroot 那个Legacy config options里面的某些配置就会这样,我之前选过那里面的也出现这种问题。毕竟这是旧版本的什么选项,估计用了就不能和配置的一起用吧。我没整明白,后来去掉了里面的选项就可以了。
1硬件&需求,licheepi_nano一块(其实什么板子都不重要能上linux能驱动LCD就可以了),环境虚拟机Ubuntu18.04 文字有点长整个过程其实用不了多少时间
我这是一次就通过了也没啥大毛病,比想象中的简单多了。
上面就是我的渣渣板了,屏幕好像是野火的一块电容屏,整了一个块板子给连上还挺好用,这都不是重点。
2.新建个目录然后下载wget http://mirrors.sohu.com/qt-all/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.tar.gz
这是QT的包,你如果不想要4.8.7那你可以下载其他版本的,当然其他版本的配置可能就不同了,不过大体是这样,别问我为什么用4.8.7因为我
刚好有这个的项目需求,咱只说过程。 tar -xzvf qt-everywhere-opensource-src-4.8.7.tar.gz 解压。
3.进入qt源码包跟目录,然后编辑vim mkspecs/linux-arm-gnueabi-g++/qmake.conf 然后修改成你自己的编译工具链我这里用的是arm-none-linux-gnueabi所以我统一修改
修改前
修改后
4.配置 这里实际肯定是需要g++来编译qmake的不过我相信能搞qt了工具链这些肯定会装的就不多说了。QT根目录运行如下命令。
./configure -release -xplatform linux-arm-gnueabi-g++ -prefix /opt/qt4.8.7_armlib -opensource -confirm-license -qt-sql-sqlite -qt-gfx-linuxfb -plugin-sql-sqlit -no-qt3support -no-phonon -no-svg -no-webkit -no-javascript-jit -no-script -no-scripttools -no-declarative -no-declarative-debug -qt-zlib -no-gif -qt-libtiff -qt-libpng -no-libmng -qt-libjpeg -no-rpath -no-pch -no-3dnow -no-avx -no-neon -no-openssl -no-nis -no-cups -no-dbus -embedded arm -platform linux-g++ -little-endian -qt-freetype -no-opengl -no-glib -nomake demos -nomake examples -nomake docs
简单说明下,如果需要知道详细可以./configure --help
-release:编译的是release版本
-xplatform: 指定交叉编译器配置的目录(读取里面的qmake.config。里面我们修改了编译工具,就是你编译运行的最终库是在什么平台(我们这里是arm上)运行的。)
-platform: 我这里没加因为默认是linux-g++。这个不要和上面那个混淆了,这个是编译qmake用的,因为需要使用qmake来生成qt的工程和makefile。其实就是指定你交叉编译的平台主机,简单说明就是你写程序和编译程序的平台。
-prefix:指定安装目录,根据自己喜好。
-opensource:表示开源许可
主要的也就是这几个关键的东西了
5.make -j8 这个后面这个8可以 windows下任务栏 性能CPU,看有几个逻辑处理器 就用几个,这样编译的快。虚拟机的话可能看分配了几个吧。
6.安装库make install 这样就会拷贝编译好的库到你prefix 指定的目录下。 结果如下图
7.qt库目录下有个bin里面有个qmake这好东西记住了,然后lib下就是编译的arm下的一些动态库了,这个我们等会要拷贝到荔枝派上的。
8. 然后随便在哪新建个目录 mkdir helloworld 然后创建个hello.cpp输入如下代码:
#include<QApplication>
#include<QLabel>
int main(int argc, char** argv)
{
QApplication app(argc,argv);
QLabel *label = new QLabel("Hello wyhcan!");
label->setGeometry(300,100,200,200);
label->show();
return app.exec();
}
然后就的用上我们上面说的qmake了。没有加入查找目录就带上路径运行qmake
在hello.cpp 目录下
1. qmake -project 生成helloworld.pro 这个名字是根据你的工程目录名字来命令的
2. qmake helloworld.pro 生成Makefile
3. make 生成可运行程序helloworld
9.最后将 prefix 你指定库目录下的lib里的所有文件拷贝到荔枝派的linux根目录的lib下,这里还有一个库 就是libstdc++.so.6这个c库也需要拷贝,至于这个文件就在你指定的工具链的lib里面 具体可以使用find 搜索到。最后拷贝记得把你的运行程序helloworld也拷贝到你的开发板上。
上电运行./heloworld -qws。
然后你可能会遇到 Cannot create semaphore /tmp/qtembedded -0的错误这是因为Qt需要用到 System V IPC进程通讯,这个时候你需要重新配置内核搜索 System V IPC 然后开启重新编译更换内核,正常情况下这个选项应该是在General setup里面。
10.搞好再运行。
这是LWIP 路由器里能看到获取IP,但ping不通
[main.c@0088]:Build DateTime:Sep 15 2020 11:43:50
[main.c@0089]:Project Name:PIC24FJ512GB606
[main.c@0094]:RN4870 Init:Success
[main.c@0100]:Set BLE Name:Success
netif: netmask of interface set to 255.255.255.0
netif: GW address of interface set to 192.168.6.1
netif_set_ipaddr: netif address being changed
netif: added interface en IP addr 192.168.6.123 netmask 255.255.255.0 gw 192.168.6.1
netif: setting default interface en
etharp_request: sending ARP request.
etharp_raw: sending raw ARP packet.
ethernet_output: sending packet 528e
dhcp_start(netif=60a2) en0
dhcp_start(): mallocing new DHCP client
dhcp_start(): allocated dhcpdhcp_start(): starting DHCP configuration
dhcp_discover()
transaction id xid(0)
dhcp_discover: making request
dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)
ip4_output_if: en0
IP header:
+-------------------------------+
| 4 | 5 | 0x00 | 336 | (v, hl, tos, len)
+-------------------------------+
| 0 |000| 0 | (id, flags, offset)
+-------------------------------+
| 255 | 17 | 0xba9d | (ttl, proto, chksum)
+-------------------------------+
| 0 | 0 | 0 | 0 | (src)
+-------------------------------+
| 255 | 255 | 255 | 255 | (dest)
+-------------------------------+
ip4_output_if: call netif->output()
ethernet_output: sending packet 52c6
dhcp_discover: deleting()ing
dhcp_discover: SELECTING
dhcp_discover(): set request timeout 2000 msecs
[main.c@0122]:netif_is_link_up.
etharp_timer
etharp_timer
dhcp_fine_tmr(): request timeout
dhcp_timeout()
dhcp_timeout(): restarting discovery
dhcp_discover()
transaction id xid(0)
dhcp_discover: making request
dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)
ip4_output_if: en0
IP header:
+-------------------------------+
| 4 | 5 | 0x00 | 336 | (v, hl, tos, len)
+-------------------------------+
| 1 |000| 0 | (id, flags, offset)
+-------------------------------+
| 255 | 17 | 0xba9c | (ttl, proto, chksum)
+-------------------------------+
| 0 | 0 | 0 | 0 | (src)
+-------------------------------+
| 255 | 255 | 255 | 255 | (dest)
+-------------------------------+
ip4_output_if: call netif->output()
ethernet_output: sending packet 52c6
dhcp_discover: deleting()ing
dhcp_discover: SELECTING
dhcp_discover(): set request timeout 4000 msecs
etharp_timer
etharp_timer
etharp_timer
etharp_timer
dhcp_fine_tmr(): request timeout
dhcp_timeout()
dhcp_timeout(): restarting discovery
dhcp_discover()
transaction id xid(0)
dhcp_discover: making request
dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)
ip4_output_if: en0
IP header:
+-------------------------------+
| 4 | 5 | 0x00 | 336 | (v, hl, tos, len)
+-------------------------------+
| 2 |000| 0 | (id, flags, offset)
+-------------------------------+
| 255 | 17 | 0xba9b | (ttl, proto, chksum)
+-------------------------------+
| 0 | 0 | 0 | 0 | (src)
+-------------------------------+
| 255 | 255 | 255 | 255 | (dest)
+-------------------------------+
ip4_output_if: call netif->output()
ethernet_output: sending packet 52c6
dhcp_discover: deleting()ing
dhcp_discover: SELECTING
dhcp_discover(): set request timeout 8000 msecs
etharp_timer
etharp_timer
etharp_timer
etharp_timer
etharp_timer
ethernet_input: dest:22:33:44:55:08:00, src:45:00:01:50:00:02, type:0
etharp_timer
ethernet_input: dest:11:22:33:44:55:08, src:00:45:00:01:50:00, type:200
etharp_timer
etharp_timer
dhcp_fine_tmr(): request timeout
dhcp_timeout()
dhcp_timeout(): restarting discovery
dhcp_discover()
transaction id xid(0)
dhcp_discover: making request
dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, LWIP_IANA_PORT_DHCP_SERVER)
ip4_output_if: en0
IP header:
+-------------------------------+
| 4 | 5 | 0x00 | 336 | (v, hl, tos, len)
+-------------------------------+
| 3 |000| 0 | (id, flags, offset)
+-------------------------------+
| 255 | 17 | 0xba9a | (ttl, proto, chksum)
+-------------------------------+
| 0 | 0 | 0 | 0 | (src)
+-------------------------------+
| 255 | 255 | 255 | 255 | (dest)
+-------------------------------+
ip4_output_if: call netif->output()
ethernet_output: sending packet 52c6
dhcp_discover: deleting()ing
dhcp_discover: SELECTING
dhcp_discover(): set request timeout 16000 msecs
etharp_timer
etharp_timer
etharp_timer
etharp_timer
etharp_timer
ethernet_input: dest:22:33:44:55:08:00, src:45:00:01:50:00:03, type:0
etharp_timer
ethernet_input: dest:11:22:33:44:55:08, src:00:45:00:01:50:00, type:300
etharp_timer
etharp_timer
etharp_timer
etharp_timer
etharp_timer
etharp_timer
etharp_timer
看你这里 输出的log来说好像是发现了DHCP服务器,然后发送什么请求(是请求IP地址?)。前面的好几个都是失败的,最后这个是log是请求成功了吗?type一个是0一个是300的你看下表示的是啥东西?我没遇到过这情况不是很清楚,看两个input数据看起来好像丢了数据一样的,第二条比第一条dest左移了还是丢失了一个字节, src就想又移了一个字节一样的。是哪里啥问题咩?
楼主,下边这个问题怎么解决呢?
这是个16位的单片机,XC16编译器,是编译器不支持吗?
#define PACK_STRUCT_BEGIN __packed[main.c@0092]:Project Name:PIC24FJ512GB606
[main.c@0097]:RN4870 Init:Success
[main.c@0103]:BM64 Init:Success
[main.c@0104]:DSP Init:Success
Assertion "Struct packing not implemented correctly. Check your lwIP port." failed at line 340 in src/lwip-2.1.2/src/core/init.c
ABRT
你把 lwipopts.h的那个 MEM_ALIGNMENT 4 四字节对齐 改成MEM_ALIGNMENT 2 两字节试试。
vip888888 说:你可以看下别人怎么搞的。我试过可以。
分享Nano fc100s linux主线5.2(TF卡)+adb+lcd(800*480)+qt5的编译过程
http://whycan.cn/t_3211.html
(出处:哇酷开发者社区【全志 V3S/F1C100s/X3】)https://whycan.cn/files/members/4270/1_20200912-1817.png
一样的步骤,卡死在这里
还真别说,当时我好像还真是遇到了一样的问题=。=。后来我好像是用uboot命令把内核加载到了另外一个地址设备树也是。然后把zImage换成了uImage
反正你只要加载到ram上运行应该就可以了。具体是改了哪个忘记了。明天回去试下看先。
我用了官方那个tf-zimage可以了,但是自己编译的不知道为什么不行,下载完我直接编译sunxi_defconfig,然后在编译出来zimage,这样有问题吗
你可以看下别人怎么搞的。我试过可以。
分享Nano fc100s linux主线5.2(TF卡)+adb+lcd(800*480)+qt5的编译过程
http://whycan.cn/t_3211.html
(出处:哇酷开发者社区【全志 V3S/F1C100s/X3】)
我又发现了另外一个开源的TCP/IP 协议栈,竟然直接支持ENC424J600,自带Driver,楼主有兴趣没,整个移植教程:)
https://www.oryx-embedded.com/products/CycloneTCP
https://whycan.cn/files/members/4881/2020-09-12_114303.png
https://whycan.cn/files/members/4881/072941fc66oyk4chlgowkc.jpg
=。=没事移植辣么多协议栈干哈,下次做玩具玩了。
楼主,能否出个教程,移植LWIP2.1.2最新版的,网上普遍1.4的,结构不大一样,以前只用过uIP1.0,LWIP还是初次接触,芯片用的ENC424J600,UIP的已经移植没问题的,想试试LWIP,我是使用PIC24FJ512GB606
你说的这个ENC424J600我没有我上网查了下这个芯片还是内置PHY和MAC层,此芯片的驱动我就不说了自行完成接收和发送帧,封装成一个发送函数一个接收函数这个没问题吧?,我们就说LWIP协议移植的关键点在哪。你看我给的整个例子LWIP是直接下载的。然后你看我初始化的时候提供的东西就知道了。因为你使用的是以太网卡所以配置那里开启#define LWIP_ETHERNET 1 这个置1就行,我没用所以我置0了。然后你将协议栈里面netif文件夹里ethemet.c加进工程,然后初始化的时候加入你自己的初始化。
然后基本上每张网卡的初始化就是一个struct netif结构。你去看下此结构就明白需要给什么了。实际上需要物理层提供的东西1.一个网卡包发送函数初始化到netif结构体上,2一个接收到网卡数据包函数当然这里接收到的数据需要用数据结构 struct pbuf链表连起来。然后像我给的例子一样调用下面处理函数就行了。
if (netif->input(p, netif) != ERR_OK) {
pbuf_free(p);
}
还是没明白是怎么把 串口当成网口 用的。
是否是这样:
板子端 是 slipif.c 来实现,电脑端 是 sudo ifconfig sl0 2.23.29.180 pointtopoint 2.23.29.160 up 来实现 ?
LWIP可以将需要传输的数据打包成TCP的数据包(传输层),正常情况下需要使用网卡(物理层)将数据传送到另外的机器上同时另外机器上也有网卡去接收这里的数据,然后再解析TCP数据包。这里等LWIP将TCP数据包打包之后直接通过串口发送出去(这里也不是直接裸发,因为要定义串口自己的一种收发协议SLIP),然后Linux上运行slattach 完成串口数据的解析还原TCP数据包。
在TCP通讯完成的情况下实现一个网页的传输,让浏览器可以访问并显示。
我们在工程目录下创建LWIP-HTTP目录,然后将协议栈下 src/apps/http目录下的fs.c加入进来把原来注释的那部分代码启用。
这个时候我们可以清楚的看到http请求的数据是通过TCP传输过来的,我们在TCP接收数据的函数里去响应客户端的http请求,依旧是将数据通过tcp发送给客户端。
这里面的 fs_open 就是去读取一个网页的数据,就是客户端请求哪个网页或者是哪张图片。网页的数据都通过软件转为了数据存储起来,网页文件数据在fsdata.c里面。
在lwip协议栈的src\apps\http\makefsdata下有把网页和图片生成fsdata.c的程序。我们可以把上一目录的fs文件夹拷贝到此目录下然后如下图运行makefsdata程序如果你无法运行,也可以编译那个.c来运行程序会把fs下的所有网页(可以修改里面的网页或者自己新增都可以)或者图片打包成一个fsdata.c这个文件拷贝到上一目录就是新的了。
到此整个过程就完毕了,如果自己动手亲自去移植并且理解下代码,可以非常深的加深自己对于http,tcp,网卡他们之间的关系的理解了。网卡(串口)完成的就是物理层的传输协议。tcp是传输层的协议。http又是架在tcp通讯上的一层应用协议。至此如果以后遇到抓什么http协议之类的。妥妥的可以直接通过TCP把http的数据整块的偷出来了。再底层一点甚至可以直接从网卡上将数据抓出来,然后将数据从自己的协议栈解析并且把数据全部暴露出来。
协议栈已经跑起来,然后我们来说说tcp和http问题。
我们经常会遇到Http协议或者TCP协议,这里做一个简单的说明。
TCP协议是在传输层,HTTP协议在应用层,Http协议是建立在TCP协议基础之上的,当我们的浏览器从服务器获取网页数据时,会发出一次Http请求。Http会通过TCP建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接。所谓的无状态,是指浏览器每次向服务器发起请求的时候,不是通过一个连接,而是每次都建立一个新的连接。如果是一个连接的话,服务器进程中就能保持住这个连接并且在内存中记住一些信息状态。而每次请求结束后,连接就关闭,相关的内容就释放了,所以记不住任何状态,成为无状态连接。
可能很多人都知道这个,但是又不知道怎么去理解它。那么针对这个问题我们上面已经移植了协议栈,这个时候我们就可以通过协议栈将板子开启tcp服务器了。既然都说http是建立在TCP协议之上的,那么我们首先要实现TCP的一个传输通讯,接着上章的工程这里我从样例里随便改了下实现tcpserver的一个例子代码如下同上下载后重新命名.c即可。
tcp_echoserver.gz
在主函数中调用tcp_echoserver_init();初始化即可一个开启tcp服务器了。
然后我在dispose_recv_data(struct tcp_pcb *tpcb, struct tcp_echoserver_struct *es)(tcp_echoserver.c里面)这是tcp接收到数据后的一个处理函数
在这里我将接收到的数据返回给客户端。
启动程序,然后我在linux下用python写了个脚本tcp.py去连接我们的板子,看是否可以完成tcp的通讯。
import socket
if __name__ == '__main__':
user_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('connect...')
user_sock.connect(('2.23.29.160',80))
print('send message')
pStr =''.join (str(i%10) for i in range(200))
user_sock.send(pStr)
ret = user_sock.recv(4096)
print('recv:%s' %ret.decode())
user_sock.close()
运行 python tcp.py 发送收据然后又接收到板子返回的数据。至此我们基于lwip协议栈的tcp数据传输就已经可以了。
阐述下此实验目的,就是通过移植lwip协议栈在MCU上完成一个服务器,从浏览器访问板子的网页。
先来张B图瞅瞅
需求:一块板子 ram有10几K就行,一个串口(我们使用串口去替代网卡(slip协议),方便大家学习与理解)。
1.我这手里是刚好有块STM32L476VGT6的板子,我就移植到此板子测试。
2.快速操作STM32Cube直接生成MDK V5的工程,开启串口1,波特率9600,开启串口接收中断如下图所示,一分钟启动。
3.去 http://download.savannah.nongnu.org/releases/lwip/ 我这直接往下拉然后下载了个最新的lwip-2.1.2.zip。然后解压没毛病。
4.将整个解压的协议栈拷贝到工程目录下,然后在MDK上新建三个目录 LWIP-NETIF, LWIP-CORE,LWIP-API。然后将协议栈里src目录下的netif的slipif.c加入到目录LWIP-NETIF中(因为我们要用串口代替网卡完成骚操作),将src中core目录下所有.c以及ipv4里所以.c加入到LWIP-CORE中(ipv6不用),最后将src的api所有文件加到LWIP-API中完整如下图所示。将src\include 加入到头文件搜索目录。
5.编译一下,会发现没有 lwipopts.h这头文件,没事我们自己定义这个头文件(主要是用来配置自己所需要的功能)
#ifndef LWIP_HDR_LWIPOPTS_H
#define LWIP_HDR_LWIPOPTS_H
//#define LWIP_DEBUG 1
#define MEM_ALIGNMENT 4
#define NO_SYS 1
#define SYS_LIGHTWEIGHT_PROT 0
#define LWIP_NETCONN 0
#define LWIP_SOCKET 0
#define LWIP_ETHERNET 0
#define LWIP_ARP 0
#define MEM_SIZE 4096
#define TCP_SND_QUEUELEN 6
#define TCP_SNDLOWAT 1071
#define PBUF_POOL_SIZE 5
#endif
我这里从简配置如上,小巧玲珑贼香。
再编译还是报错没有#include "arch/cc.h" 看注解,我们明显有memset可用,所以这里直接不加入这个头文件,注释后面加
#define PACK_STRUCT_BEGIN __packed 因为lwip协议栈用这个宏对齐,所以定义 __packed这个对齐操作。
继续编译结果如下
这几个没有实现的函数就很重要的了进入下一步详解。
6.
第一个 sio_open 就是打开串口的一个函数用户需要自己实现这个函数并返回一个sio_fd_t
第二个sio_send函数这个就是完成字符发送的一个函数实现
第三个sio_tryread函数系统读取接收到的数据的一个接口
第四个sys_now 就是给一个ms的变化值类似于提供时钟节拍。
我这里定义了一个lwip_app.c完成了上述4个函数并增加了lwip_app_init函数。因为不能上传.c后缀这里把后缀改为了.gz下载后重命名即可。
lwip_app.gz
如下图在main函数中加入下面三个函数即可
编译完成没毛病,然后在串口中断函数中加入接收缓存
下面为串口1中断接收函数,将数据缓存给slipif使用。
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint8_t Res;
if((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET))
{
HAL_UART_Receive(&huart1, &Res, 1, 1000);
extern void sio_setData(uint8_t data); //此函数在lwip_app中接收串口数据缓存
sio_setData(Res);
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
至此已经完成了lwip的移植,开启了tcp功能。
下面进行骚操作,整个虚拟机装个Linux。然后将ttl转USB的串口接入到Linux中
1.打开一个终端运行 sudo slattach /dev/ttyUSB0 -p slip -s 9600 -m -d 这里的ttyUSB0就是接入的ch430的ttl转USB接口。如果没有slattach命令可以根据提示安装即可。
2.sudo ifconfig sl0 2.23.29.180 pointtopoint 2.23.29.160 up。第一个IP在板子里设置为网关,第二个IP就是板子自己的IP用于通讯。
3.设置完可以使用ifconfig 查看就多了新增的网卡了结果如下图所示:
然后板子上电启动。在linux终端下ping 2.23.29.160然后就会神奇的通过了,而且是通过串口连通的。
有兴趣的可以看看slipif.c文件没多少代码 研究研究就可以理解了。这里无非是把网卡做的事变成了串口来进行数据传输。从这里可以看出如果我们需要用网卡进行数据传输需要完成哪部分功能,需要给协议栈什么东西就很容易理解了。
1.使用STM32Cube 直接先配置串口1的基础信息。
2.然后配置DMA传输
3.就是启动了,在串口初始化之后默认是没有开启串口DMA接收的。所以增加几行代码如下图所示
4.写串口1中断函数:
这个函数就是实现不等长的精髓所在了。这里用到了类似环形队列的方法,至于什么是环形队列这个不知道童鞋自行Google了。
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&systemUart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_FLUSH_DRREGISTER(&systemUart); //清除 IDLE中断
}
HAL_UART_IRQHandler(&systemUart);
}
首先将中断函数写出来,如上所示了。这时候帧中断的时候会进这个中断,数据用DMA接收。
第二步建立对应变量
#define UART1_DMA_DATA_LEN 100//数据最大长度
static UART_HandleTypeDef systemUart;
DMA_HandleTypeDef hdma_usart1_rx;
static uint8_t _uartDmaDataBuffer[UART1_DMA_DATA_LEN]; //缓冲区就是初始化的时候用到的
static int dmaDataTail = 0; //将DMA数据传输Buffer 虚拟成一个队列缓冲区
static int dmaDataHead = 0;
static int dmaDataLenght = 0;
第三步实现类似环形队列功能
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&systemUart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_FLUSH_DRREGISTER(&systemUart); //清除 IDLE中断
dmaDataTail = hdma_usart1_rx.Instance->NDTR;
dmaDataTail = UART1_DMA_DATA_LEN - dmaDataTail;
dmaDataLenght = (dmaDataTail - dmaDataHead+UART1_DMA_DATA_LEN) % UART1_DMA_DATA_LEN; //求数据长度
}
HAL_UART_IRQHandler(&systemUart);
}
注意里面 hdma_usart1_rx.Instance->NDTR的NDTR不同的型号可能不同可以在DMA的结构体里找到对应的名字,如下图所示
这个NDTR的值是从UART1_DMA_DATA_LEN开始递减的,因为启动DMA的时候设置了传输长度为UART1_DMA_DATA_LEN
所以我们接收到当前的数据下标就是UART1_DMA_DATA_LEN - hdma_usart1_rx.Instance->NDTR这个。这个其实就是当前接收到数据的结束下标。有了数据结束下标,我们还需要数据起始下标,以及数据长度。
①数据起始下标: 等于上一次的dmaDataTail 所以每次处理完数据都有dmaDataHead = dmaDataTail;
②数据长度:这个利用环形队列求长度的做法:
dmaDataLenght = (dmaDataTail - dmaDataHead+UART1_DMA_DATA_LEN) % UART1_DMA_DATA_LEN;
现在我们有了数据起始下标 数据长度那么我们就可以访问我们的数据了。当然方法也和环形队列差不多
完成的中断函数就是这样的。可以接收什么返回什么了,要想自己处理可以在这里增加缓冲区或者调用处理函数了。
void USART1_IRQHandler(void)
{
if(__HAL_UART_GET_FLAG(&systemUart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_FLUSH_DRREGISTER(&systemUart); //清除 IDLE中断
dmaDataTail = hdma_usart1_rx.Instance->NDTR;
dmaDataTail = UART1_DMA_DATA_LEN - dmaDataTail;
dmaDataLenght = (dmaDataTail - dmaDataHead+UART1_DMA_DATA_LEN) % UART1_DMA_DATA_LEN; //求数据长度
for(int i = 0; i < dmaDataLenght; i++)
{
int index = (dmaDataHead+i)%UART1_DMA_DATA_LEN;
printf("%c",_uartDmaDataBuffer[index]);
}
printf("\r\n");
dmaDataHead = dmaDataTail;
}
HAL_UART_IRQHandler(&systemUart);
}
最后来张测试结果图分别是一顿乱操作发不同的数据长度和数据
最后注意一点的就是这个程序如果你一下子发超过100个字节那估计就不行了。因为超了缓冲区长度数据被覆盖了,当然增加长度就可以解决了。
可以试下看有没有fb0的信息,之前我也遇到过有fb0的然后cat也没用,后来发现好像是写之后需要控制layout的选择。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
int main(int argc, char **argv)
{
int fd;
/* 打开fb设备文件 */
fd = open("/dev/fb0", O_RDWR);
if (-1 == fd)
{
perror("open fb");
return -1;
}
/* 获取fix屏幕信息:获取命令为FBIOGET_FSCREENINFO */
struct fb_fix_screeninfo fixInfo;
if (ioctl(fd, FBIOGET_FSCREENINFO, &fixInfo) == -1)
{
perror("get fscreeninfo");
close(fd);
return -2;
}
/* 打印fix信息 */
printf("id = %s\n", fixInfo.id); /* 厂商id信息 */
printf("line length = %d\n", fixInfo.line_length);
/* 这里获取的是一行像素所需空间
* 该空间大小是出厂时就固定的了
* 厂商会对一行像素字节进行对齐*/
/* 获取var屏幕的信息:获取命令为FBIOGET_VSCREENINFO */
struct fb_var_screeninfo varInfo;
if (ioctl(fd, FBIOGET_VSCREENINFO, &varInfo) == -1)
{
perror("get var screen failed\n");
close(fd);
return -3;
}
/* 打印var信息 */
printf("xres = %d, yres = %d\n", varInfo.xres, varInfo.yres);
printf("bits_per_pixel = %d\n", varInfo.bits_per_pixel);
printf("red: offset = %d, length = %d\n", \
varInfo.red.offset, varInfo.red.length);
printf("green: offset = %d, length = %d\n", \
varInfo.green.offset, varInfo.green.length);
printf("blue: offset = %d, length = %d\n", \
varInfo.blue.offset, varInfo.blue.length);
printf("transp: offset = %d, length = %d\n", \
varInfo.transp.offset, varInfo.transp.length);
close(fd);
return 0;
}
这个就我个人理解,就像并口一样,假设spi时序上升沿读,下降沿写。标准情况下SPI是不是只有一根W线一根R线,一跟SCLK,一根CS(都用IO模拟)。我们首先CS选中然后控制SCLK发送一个下降沿就写1bit数据出去(一个字节8bit),所以要写一个字节SCLK就需要控制8次的下降沿来完成。那么如果说我接了8块SPI flash(姑且就 W25Q64吧)。假设我模拟怎么接呢? 我用一个SCLK将8个W25Q64的SCLK接到一起 CS也接到一起,W用PA0-PA7分别接到8块W25Q64的W上。R用PB0-PB7分别接到8块W25Q64的R上。这样的话我CS一选就选定了8块,我要传输一个字节那么我只需要让SCLK产生一次下降沿,然后把一个字节的8bit对应放到PA0-PA7上。那么我这种模拟的SPI应该就算是SPI 8 bit模式了吧=。=那些2bit 4bit估计也是这样的吧。
页次: 1