0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

FreeRTOSを動かしてみる(11)

Last updated at Posted at 2023-12-21

前回の続き
受信が怪しいけど一旦つなげてみる

の前に各種パラメータを確認する。

設定内容

images

IP関連

IPアドレスなどは図の通り
macアドレスは潰れた会社のを利用

FreeRTOS <-> QEMU間

にも書いたこれ

name addr size details remarks
wlock 0x28000000 4 0:none 1:writing FreeRTOS -> qemu
wsize 0x28000004 4
wdata 0x28000010 0x100000 - 16 to 0x280fffff
rlock 0x28100000 4 0:none 1:writing qemu -> FreeRTOS
rsize 0x28100004 4
rdata 0x28100010 0x100000 - 16 to 0x281fffff

FreeRTOS -> QEMU

  1. 0x28000000 を1にする
  2. 0x28000004 にデータサイズを記載する
  3. 0x28000010 の位置からデータを貼り付ける
  4. 0x28000000 を0にする
  5. QEMU内の仮想デバイスは0x28000000 が 1から0になったタイミングで
    0x28000004に記載のサイズ分をdummyプロセスのUDPサーバ(7145)へ送信する。

QEMU -> FreeRTOS

  1. 0x28100004 に相当するバッファにデータサイズを記載する
  2. 0x28100010 に相当するバッファにデータを貼り付ける
  3. IRQ(13)(*1)を発火させて割り込みを行う
  4. FreeRTOSの割り込みハンドラが0x28100004のサイズ分のデータを
    0x28100010から読み出す

(*1) qemu管理だと29だが、FreeRTOS上では13

Linux上のアプリとダミープロセス間

アプリ <-> デバイスドライバは標準API

デバイスドライバ -> ダミープロセス

システムコールされてデバドラに入って来たデータはUDPのポート7146へ送信する。

ダミープロセス -> デバイスドライバ

  1. NICデバイスは別途キャラクタデバイスを持っており
    open -> write -> closeでデータを書き込む。
  2. closeタイミングでデータを確定させる。
    具体的にはnetif_receive_skbをコールする。

QEMUとダミープロセス間

待ち受けはANYIPで、送信先はLoopback(127.0.0.1)にする。

direction source port target port
QEMU -> dummy process ephemeral port 7145
dummy process -> QEMU ephemeral port 7144

Linuxのデバドラから直でQEMUに送れば2回もUDP挟む必要がないのだけど
所詮ロケハンなので良しとしよう。

その他

  • IPv6には非対応
  • 並列送信には非対応

実装

実行結果

先にLinux側を立ち上げて

virtether$ ./run.sh 1
make -C /lib/modules/6.5.6-300.fc39.x86_64/build M=/home/voyager/workspace/freertos/virtether modules
make[1]: Entering directory '/usr/src/kernels/6.5.6-300.fc39.x86_64'
warning: the compiler differs from the one used to build the kernel
  The kernel was built by: gcc (GCC) 13.2.1 20230918 (Red Hat 13.2.1-3)
  You are using:           gcc (GCC) 13.2.1 20231205 (Red Hat 13.2.1-6)
make[1]: Leaving directory '/usr/src/kernels/6.5.6-300.fc39.x86_64'
EXTRA_CLAGS="-g -DDEBUG"
insmod: ERROR: could not insert module virtether.ko: File exists
RTNETLINK answers: File exists
    try:
        ping -w1 192.168.100.2
        sudo echo "aiueo" > /dev/veth_cdev 
virtether$ echoback.c(83) main queue:(nil)
echoback.c(144) recv_main bind

FreeRTOSを起動すると

CORTEX_M3_MPS2_QEMU_GCC$ sudo /home/voyager/workspace/oss/build_qemu/qemu-system-arm -machine mps2-an385 -m 16 -monitor null -semihosting --semihosting-config enable=on,target=native -kernel ./build/RTOSDemo.axf -serial stdio -nographic 2>&1 | tee -a qemu.log 
mps2.c(666) add_extra_mmio_an385 added to 28000000
mps2.c(794) udp_recvfromdummy 
mps2.c(282) mps2_common_init armv7m:0x5611aa220760 mms->armv7m:0x5611aa220760
[0000] main_tcp.c(23) main_tcp Build: 14:08:07, Dec 21 2023(9d5637f290cda3dd8bc60f4be6af90f882f63851) fr:0x1e7 
[0000] NetworkInterface.c(138) pxFillInterfaceDescriptor mac:0 fr:0x53c7 
[1c80] NetworkInterface.c(214) ether_task smph:0x20112d50 fr:0x2a1 
[67ac] FreeRTOS_IP.c(1398) xSendEventStructToIPTask et:0 fr:0x573d 
[67ac] FreeRTOS_IP.c(1418) xSendEventStructToIPTask  fr:0x573d 
[67ac] FreeRTOS_IP.c(1428) xSendEventStructToIPTask xReturn:1 fr:0x573d 
[24b8] app_server.c(14) server_task  fr:0x2a1 
[24b8] app_server.c(31) vCreateTCPServerSocket sock:537996712 fr:0xda0d 
[24b8] FreeRTOS_IP.c(1398) xSendEventStructToIPTask et:9 fr:0x995d 
[24b8] FreeRTOS_IP.c(1418) xSendEventStructToIPTask  fr:0x995d 
[2cf0] app_client.c(28) client_task  fr:0x2a1 
[24b8] FreeRTOS_IP.c(1428) xSendEventStructToIPTask xReturn:1 fr:0x995d 
[24b8] app_server.c(46) vCreateTCPServerSocket bind fr:0xda0d 
[24b8] app_server.c(49) vCreateTCPServerSocket listen fr:0xda0d 

勝手になんか飛んでるぞ

mps2.c(751) udp_send2dummy sz:42
[67ac] NetworkInterface.c(180) pfOutput ip:264a8c0 po:0 bp:0 len:42 r:1 data:
ff ff ff ff ff ff aa 00 02 aa bb cc 08 06 00 01
08 00 06 04 00 01 aa 00 02 aa bb cc c0 a8 64 02
00 00 00 00 00 00 c0 a8 64 02 
 fr:0x3d4d 

Linux側でも受け取れてるっぽい

echoback.c(243) send_callback write:42
echoback.c(83) main queue:(nil)
echoback.c(179) recv_main cond signal
echoback.c(83) main queue:0x7f65b4000c60
echoback.c(87) main ff ff ff ff ff ff aa 00 02 aa bb cc 08 06 00 01
08 00 06 04 00 01 aa 00 02 aa bb cc c0 a8 64 02
00 00 00 00 00 00 c0 a8 64 02 

よし、pingを飛ばすぞ

virtether$ ping -w1 192.168.100.2
PING 192.168.100.2 (192.168.100.2) 56(84) bytes of data.
echoback.c(262) send_udp sendto(98): 98
echoback.c(179) recv_main cond signal
echoback.c(83) main queue:0x7f3ce4000df0
echoback.c(87) main aa 00 02 11 22 33 aa 00 02 aa bb cc 08 00 45 00
00 54 91 ec 00 00 40 01 9f 68 c0 a8 64 02 c0 a8
64 01 00 00 e5 83 00 44 00 01 e2 d7 83 65 00 00
00 00 e8 26 0d 00 00 00 00 00 10 11 12 13 14 15
16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25
26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35
36 37 

echoback.c(243) send_callback write:98
echoback.c(83) main queue:(nil)
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=31.0 ms

--- 192.168.100.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 30.959/30.959/30.959/0.000 ms

通った

小ネタ

semaphoreで起こすやり方は割り込みハンドラの優先度がconfigMAX_SYSCALL_INTERRUPT_PRIORITY以上でないとだめらしい

#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )    xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )

160     #ifdef configASSERT
161         void vPortValidateInterruptPriority( void );
162         #define portASSERT_IF_INTERRUPT_PRIORITY_INVALID()    vPortValidateInterruptPriority()
163     #endif

1212 BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
1213                               BaseType_t * const pxHigherPriorityTaskWoken )
...
1250     portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

240         ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
...
607     void vPortValidateInterruptPriority( void )
608     {
609         extern uint32_t ulPortGetIPSR( void );
610         uint32_t ulCurrentInterrupt;
611         uint8_t ucCurrentPriority;
612 
613         ulCurrentInterrupt = ulPortGetIPSR();
614 
615         /* Is the interrupt number a user defined interrupt? */
616         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
617         {
618             /* Look up the interrupt's priority. */
619             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
...
644             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );

なのでこんな感じにしました。

static void set_eth_irq(void)
{
    NVIC_EnableIRQ(ETHERNET_IRQn);
    NVIC->IP[ETHERNET_IRQn] = configMAX_SYSCALL_INTERRUPT_PRIORITY;
}

void _start(void)
{
    uart_init();
    set_eth_irq();
    main(0, 0);
    exit(0);
}

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?