基于DWC_ether_qos的以太网驱动开发-RTOS环境移植LWIP与性能测试

原创 嵌入式Lee 2023-09-10 07:31

一. 前言

前面我们基于无OS环境移植了LWIP,这一篇我们来基于RTOS移植LWIP,与无OS环境基本一致,只是需要实现一些系统组件的接口,信号量互斥量等。

二. 需要移植文件

我们参考lwip\contrib\ports\freertos下的移植进行修改,如果使用的是freertos的话直接参考即可。如果用的其他RTOS可以复制一份修改。

复制lwip\contrib\ports\freertos并添加cc.hlwipopts.h(这两个文件可以从contrib下其他样例代码中复制)

 

Cc.h

还是和无OS一样实现随机数函数

#ifndef LWIP_ARCH_CC_H#define LWIP_ARCH_CC_H
#include
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__);} while(0)
extern uint32_t lwip_port_rand(void);#define LWIP_RAND() (lwip_port_rand())
#endif

Sys_arch.h/sys_arch.c

如果使用的freertos直接使用即可,否则按需修改。

相关接口。

/* * Copyright (c) 2017 Simon Goldschmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmdit  * */#ifndef LWIP_ARCH_SYS_ARCH_H#define LWIP_ARCH_SYS_ARCH_H
#include "lwip/opt.h"#include "lwip/arch.h"
/** This is returned by _fromisr() sys functions to tell the outermost function * that a higher priority task was woken and the scheduler needs to be invoked. */#define ERR_NEED_SCHED 123
/* This port includes FreeRTOS headers in sys_arch.c only. * FreeRTOS uses pointers as object types. We use wrapper structs instead of * void pointers directly to get a tiny bit of type safety. */
void sys_arch_msleep(u32_t delay_ms);#define sys_msleep(ms) sys_arch_msleep(ms)
#if SYS_LIGHTWEIGHT_PROTtypedef u32_t sys_prot_t;#endif /* SYS_LIGHTWEIGHT_PROT */
#if !LWIP_COMPAT_MUTEXstruct _sys_mut { void *mut;};typedef struct _sys_mut sys_mutex_t;#define sys_mutex_valid_val(mutex) ((mutex).mut != NULL)#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex)))#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL)#endif /* !LWIP_COMPAT_MUTEX */
struct _sys_sem { void *sem;};typedef struct _sys_sem sys_sem_t;#define sys_sem_valid_val(sema) ((sema).sem != NULL)#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema)))#define sys_sem_set_invalid(sema) ((sema)->sem = NULL)
struct _sys_mbox { void *mbx;};typedef struct _sys_mbox sys_mbox_t;#define sys_mbox_valid_val(mbox) ((mbox).mbx != NULL)#define sys_mbox_valid(mbox) (((mbox) != NULL) && sys_mbox_valid_val(*(mbox)))#define sys_mbox_set_invalid(mbox) ((mbox)->mbx = NULL)
struct _sys_thread { void *thread_handle;};typedef struct _sys_thread sys_thread_t;
#if LWIP_NETCONN_SEM_PER_THREADsys_sem_t* sys_arch_netconn_sem_get(void);void sys_arch_netconn_sem_alloc(void);void sys_arch_netconn_sem_free(void);#define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get()#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc()#define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free()#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#endif /* LWIP_ARCH_SYS_ARCH_H */


/* * Copyright (c) 2017 Simon Goldschmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt  * */
/* lwIP includes. */#include "lwip/debug.h"#include "lwip/def.h"#include "lwip/sys.h"#include "lwip/mem.h"#include "lwip/stats.h"#include "lwip/tcpip.h"#include "FreeRTOS.h"#include "semphr.h"#include "task.h"
/** Set this to 1 if you want the stack size passed to sys_thread_new() to be * interpreted as number of stack words (FreeRTOS-like). * Default is that they are interpreted as byte count (lwIP-like). */#ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS#define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS 0#endif
/** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions. * Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT(). */#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX#define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX 0#endif
/** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and * SYS_ARCH_UNPROTECT() are called matching. */#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK#define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK 0#endif
/** Set this to 1 to let sys_mbox_free check that queues are empty when freed */#ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE#define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE 0#endif
/** Set this to 1 to enable core locking check functions in this port. * For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED() * and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */#ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING#define LWIP_FREERTOS_CHECK_CORE_LOCKING 1#endif
/** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer. * Default is 1, where FreeRTOS ticks are used to calculate back to ms. */#ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS#define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS 1#endif
#if !configSUPPORT_DYNAMIC_ALLOCATION# error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION"#endif#if !INCLUDE_vTaskDelay# error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay"#endif#if !INCLUDE_vTaskSuspend# error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend"#endif#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX#if !configUSE_MUTEXES# error "lwIP FreeRTOS port requires configUSE_MUTEXES"#endif#endif
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEXstatic SemaphoreHandle_t sys_arch_protect_mutex;#endif#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECKstatic sys_prot_t sys_arch_protect_nesting;#endif
/* Initialize this module (see description in sys.h) */voidsys_init(void){#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX /* initialize sys_arch_protect global mutex */ sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex(); LWIP_ASSERT("failed to create sys_arch_protect mutex", sys_arch_protect_mutex != NULL);#endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */}
#if configUSE_16_BIT_TICKS == 1#error This port requires 32 bit ticks or timer overflow will fail#endif
#if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOSu32_tsys_now(void){ return xTaskGetTickCount() * portTICK_PERIOD_MS;}#endif
u32_tsys_jiffies(void){ return xTaskGetTickCount();}
#if SYS_LIGHTWEIGHT_PROT
sys_prot_tsys_arch_protect(void){#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX BaseType_t ret; LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY); LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE);#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ taskENTER_CRITICAL();#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK { /* every nested call to sys_arch_protect() returns an increased number */ sys_prot_t ret = sys_arch_protect_nesting; sys_arch_protect_nesting++; LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret); return ret; }#else return 1;#endif}
voidsys_arch_unprotect(sys_prot_t pval){#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX BaseType_t ret;#endif#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0); sys_arch_protect_nesting--; LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval);#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex); LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE);#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ taskEXIT_CRITICAL();#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ LWIP_UNUSED_ARG(pval);}
#endif /* SYS_LIGHTWEIGHT_PROT */
voidsys_arch_msleep(u32_t delay_ms){ TickType_t delay_ticks = delay_ms / portTICK_RATE_MS; vTaskDelay(delay_ticks);}
#if !LWIP_COMPAT_MUTEX
/* Create a new mutex*/err_tsys_mutex_new(sys_mutex_t *mutex){ LWIP_ASSERT("mutex != NULL", mutex != NULL);
mutex->mut = xSemaphoreCreateRecursiveMutex(); if(mutex->mut == NULL) { SYS_STATS_INC(mutex.err); return ERR_MEM; } SYS_STATS_INC_USED(mutex); return ERR_OK;}
voidsys_mutex_lock(sys_mutex_t *mutex){ BaseType_t ret; LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY); LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);}
voidsys_mutex_unlock(sys_mutex_t *mutex){ BaseType_t ret; LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
ret = xSemaphoreGiveRecursive(mutex->mut); LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);}
voidsys_mutex_free(sys_mutex_t *mutex){ LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
SYS_STATS_DEC(mutex.used); vSemaphoreDelete(mutex->mut); mutex->mut = NULL;}
#endif /* !LWIP_COMPAT_MUTEX */
err_tsys_sem_new(sys_sem_t *sem, u8_t initial_count){ LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("initial_count invalid (not 0 or 1)", (initial_count == 0) || (initial_count == 1));
sem->sem = xSemaphoreCreateBinary(); if(sem->sem == NULL) { SYS_STATS_INC(sem.err); return ERR_MEM; } SYS_STATS_INC_USED(sem);
if(initial_count == 1) { BaseType_t ret = xSemaphoreGive(sem->sem); LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE); } return ERR_OK;}
voidsys_sem_signal(sys_sem_t *sem){ BaseType_t ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
ret = xSemaphoreGive(sem->sem); /* queue full is OK, this is a signal only... */ LWIP_ASSERT("sys_sem_signal: sane return value", (ret == pdTRUE) || (ret == errQUEUE_FULL));}
u32_tsys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms){ BaseType_t ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
if(!timeout_ms) { /* wait infinite */ ret = xSemaphoreTake(sem->sem, portMAX_DELAY); LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); } else { TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; ret = xSemaphoreTake(sem->sem, timeout_ticks); if (ret == errQUEUE_EMPTY) { /* timed out */ return SYS_ARCH_TIMEOUT; } LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); }
/* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1;}
voidsys_sem_free(sys_sem_t *sem){ LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
SYS_STATS_DEC(sem.used); vSemaphoreDelete(sem->sem); sem->sem = NULL;}
err_tsys_mbox_new(sys_mbox_t *mbox, int size){ LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("size > 0", size > 0);
mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *)); if(mbox->mbx == NULL) { SYS_STATS_INC(mbox.err); return ERR_MEM; } SYS_STATS_INC_USED(mbox); return ERR_OK;}
voidsys_mbox_post(sys_mbox_t *mbox, void *msg){ BaseType_t ret; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY); LWIP_ASSERT("mbox post failed", ret == pdTRUE);}
err_tsys_mbox_trypost(sys_mbox_t *mbox, void *msg){ BaseType_t ret; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
ret = xQueueSendToBack(mbox->mbx, &msg, 0); if (ret == pdTRUE) { return ERR_OK; } else { LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); SYS_STATS_INC(mbox.err); return ERR_MEM; }}
err_tsys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg){ BaseType_t ret; BaseType_t xHigherPriorityTaskWoken = pdFALSE; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken); if (ret == pdTRUE) { if (xHigherPriorityTaskWoken == pdTRUE) { return ERR_NEED_SCHED; } return ERR_OK; } else { LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); SYS_STATS_INC(mbox.err); return ERR_MEM; }}
u32_tsys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms){ BaseType_t ret; void *msg_dummy; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
if (!msg) { msg = &msg_dummy; }
if (!timeout_ms) { /* wait infinite */ ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY); LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); } else { TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks); if (ret == errQUEUE_EMPTY) { /* timed out */ *msg = NULL; return SYS_ARCH_TIMEOUT; } LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); }
/* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1;}
u32_tsys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg){ BaseType_t ret; void *msg_dummy; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
if (!msg) { msg = &msg_dummy; }
ret = xQueueReceive(mbox->mbx, &(*msg), 0); if (ret == errQUEUE_EMPTY) { *msg = NULL; return SYS_MBOX_EMPTY; } LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
return 0;}
voidsys_mbox_free(sys_mbox_t *mbox){ LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
#if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE { UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx); LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
if (msgs_waiting != 0) { SYS_STATS_INC(mbox.err); } }#endif
vQueueDelete(mbox->mbx);
SYS_STATS_DEC(mbox.used);}
sys_thread_tsys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio){ TaskHandle_t rtos_task; BaseType_t ret; sys_thread_t lwip_thread; size_t rtos_stacksize;
LWIP_ASSERT("invalid stacksize", stacksize > 0);#if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS rtos_stacksize = (size_t)stacksize;#else rtos_stacksize = (size_t)stacksize / sizeof(StackType_t);#endif
/* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the thread function without adaption here. */ ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task); LWIP_ASSERT("task creation failed", ret == pdTRUE);
lwip_thread.thread_handle = rtos_task; return lwip_thread;}
#if LWIP_NETCONN_SEM_PER_THREAD#if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0
sys_sem_t *sys_arch_netconn_sem_get(void){ void* ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0); return ret;}
voidsys_arch_netconn_sem_alloc(void){ void *ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0); if(ret == NULL) { sys_sem_t *sem; err_t err; /* need to allocate the memory for this semaphore */ sem = mem_malloc(sizeof(sys_sem_t)); LWIP_ASSERT("sem != NULL", sem != NULL); err = sys_sem_new(sem, 0); LWIP_ASSERT("err == ERR_OK", err == ERR_OK); LWIP_ASSERT("sem invalid", sys_sem_valid(sem)); vTaskSetThreadLocalStoragePointer(task, 0, sem); }}
void sys_arch_netconn_sem_free(void){ void* ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0); if(ret != NULL) { sys_sem_t *sem = ret; sys_sem_free(sem); mem_free(sem); vTaskSetThreadLocalStoragePointer(task, 0, NULL); }}
#else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */#error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#if LWIP_FREERTOS_CHECK_CORE_LOCKING#if LWIP_TCPIP_CORE_LOCKING
/** Flag the core lock held. A counter for recursive locks. */static u8_t lwip_core_lock_count;static TaskHandle_t lwip_core_lock_holder_thread;
voidsys_lock_tcpip_core(void){ sys_mutex_lock(&lock_tcpip_core); if (lwip_core_lock_count == 0) { lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle(); } lwip_core_lock_count++;}
voidsys_unlock_tcpip_core(void){ lwip_core_lock_count--; if (lwip_core_lock_count == 0) { lwip_core_lock_holder_thread = 0; } sys_mutex_unlock(&lock_tcpip_core);}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if !NO_SYSstatic TaskHandle_t lwip_tcpip_thread;#endif
voidsys_mark_tcpip_thread(void){#if !NO_SYS lwip_tcpip_thread = xTaskGetCurrentTaskHandle();#endif}
voidsys_check_core_locking(void){ /* Embedded systems should check we are NOT in an interrupt context here */ /* E.g. core Cortex-M3/M4 ports: configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */ taskENTER_CRITICAL(); taskEXIT_CRITICAL();
#if !NO_SYS if (lwip_tcpip_thread != 0) { TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();
#if LWIP_TCPIP_CORE_LOCKING LWIP_ASSERT("Function called without core lock", current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0);#else /* LWIP_TCPIP_CORE_LOCKING */ LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);#endif /* LWIP_TCPIP_CORE_LOCKING */ }#endif /* !NO_SYS */}
#endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/

Lwipopts.h

配置

/** * @file * * lwIP Options Configuration */
/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */#ifndef LWIP_LWIPOPTS_H#define LWIP_LWIPOPTS_H
/* * Include user defined options first. Anything not defined in these files * will be set to standard values. Override anything you don't like! */#include "lwipopts.h"#include "lwip/debug.h"#include "os_mem.h"
#define LWIP_PROVIDE_ERRNO 1#define LWIP_COMPAT_MUTEX 0#define LWIP_DEBUG 1
#define DEFAULT_THREAD_PRIO 7#define DEFAULT_THREAD_STACKSIZE 1024#define TCPIP_THREAD_STACKSIZE 1024#define TCPIP_THREAD_PRIO 7#define SNMP_STACK_SIZE 1024#define SNMP_THREAD_PRIO 7#define SLIPIF_THREAD_STACKSIZE 1024#define SLIPIF_THREAD_PRIO 7
#define MEMP_MEM_MALLOC 1#define MEM_LIBC_MALLOC 1#define mem_clib_malloc(size) os_mem_malloc(0,size)#define mem_clib_free os_mem_free#define mem_clib_calloc(cnt,size) os_mem_calloc(0,(cnt)*(size))
#define DEFAULT_RAW_RECVMBOX_SIZE 10#define DEFAULT_UDP_RECVMBOX_SIZE 10#define DEFAULT_TCP_RECVMBOX_SIZE 10#define TCPIP_MBOX_SIZE 10#define DEFAULT_ACCEPTMBOX_SIZE 10
#define TCP_MSS (1500 - 40)
#define TCP_SND_BUF (11*TCP_MSS)#define TCP_WND (11*TCP_MSS)/* ----------------------------------------------- ---------- Platform specific locking ---------- -----------------------------------------------*/
/** * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain * critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */#define SYS_LIGHTWEIGHT_PROT 0
/** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. */#define NO_SYS 0
/* ------------------------------------ ---------- Memory options ---------- ------------------------------------*/
/** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 * 2 byte alignment -> #define MEM_ALIGNMENT 2 */#define MEM_ALIGNMENT 4U
/** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */#define MEM_SIZE 1600
/* ------------------------------------------------ ---------- Internal Memory Pool Sizes ---------- ------------------------------------------------*//** * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). * If the application sends a lot of data out of ROM (or other static memory), * this should be set high. */#define MEMP_NUM_PBUF 160
/** * MEMP_NUM_RAW_PCB: Number of raw connection PCBs * (requires the LWIP_RAW option) */#define MEMP_NUM_RAW_PCB 4
/** * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One * per active UDP "connection". * (requires the LWIP_UDP option) */#define MEMP_NUM_UDP_PCB 4
/** * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. * (requires the LWIP_TCP option) */#define MEMP_NUM_TCP_PCB 4
/** * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. * (requires the LWIP_TCP option) */#define MEMP_NUM_TCP_PCB_LISTEN 4
/** * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. * (requires the LWIP_TCP option) */#define MEMP_NUM_TCP_SEG 160
/** * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for * reassembly (whole packets, not fragments!) */#define MEMP_NUM_REASSDATA 1
/** * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. * (requires the ARP_QUEUEING option) */#define MEMP_NUM_ARP_QUEUE 2
/** * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. * (requires NO_SYS==0) */#define MEMP_NUM_SYS_TIMEOUT 8
/** * MEMP_NUM_NETBUF: the number of struct netbufs. * (only needed if you use the sequential API, like api_lib.c) */#define MEMP_NUM_NETBUF 2
/** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */#define MEMP_NUM_NETCONN 32
/** * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used * for callback/timeout API communication. * (only needed if you use tcpip.c) */#define MEMP_NUM_TCPIP_MSG_API 8
/** * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used * for incoming packets. * (only needed if you use tcpip.c) */#define MEMP_NUM_TCPIP_MSG_INPKT 8
/** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */#define PBUF_POOL_SIZE 64
/* --------------------------------- ---------- ARP options ---------- ---------------------------------*//** * LWIP_ARP==1: Enable ARP functionality. */#define LWIP_ARP 1
/* -------------------------------- ---------- IP options ---------- --------------------------------*//** * IP_FORWARD==1: Enables the ability to forward IP packets across network * interfaces. If you are going to run lwIP on a device with only one network * interface, define this to 0. */#define IP_FORWARD 0
/** * IP_OPTIONS: Defines the behavior for IP options. * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). */#define IP_OPTIONS_ALLOWED 1
/** * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */#define IP_REASSEMBLY 1
/** * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */#define IP_FRAG 1
/** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived * in this time, the whole packet is discarded. */#define IP_REASS_MAXAGE 3
/** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. * Since the received pbufs are enqueued, be sure to configure * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive * packets even if the maximum amount of fragments is enqueued for reassembly! */#define IP_REASS_MAX_PBUFS 4
/** * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP * fragmentation. Otherwise pbufs are allocated and reference the original * packet data to be fragmented.*/#define IP_FRAG_USES_STATIC_BUF 0
/** * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. */#define IP_DEFAULT_TTL 255
/* ---------------------------------- ---------- ICMP options ---------- ----------------------------------*//** * LWIP_ICMP==1: Enable ICMP module inside the IP stack. * Be careful, disable that make your product non-compliant to RFC1122 */#define LWIP_ICMP 1
/* --------------------------------- ---------- RAW options ---------- ---------------------------------*//** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */#define LWIP_RAW 1
/* ---------------------------------- ---------- DHCP options ---------- ----------------------------------*//** * LWIP_DHCP==1: Enable DHCP module. */#define LWIP_DHCP 0

/* ------------------------------------ ---------- AUTOIP options ---------- ------------------------------------*//** * LWIP_AUTOIP==1: Enable AUTOIP module. */#define LWIP_AUTOIP 0
/* ---------------------------------- ---------- SNMP options ---------- ----------------------------------*//** * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP * transport. */#define LWIP_SNMP 0
/* ---------------------------------- ---------- IGMP options ---------- ----------------------------------*//** * LWIP_IGMP==1: Turn on IGMP module. */#define LWIP_IGMP 0
/* ---------------------------------- ---------- DNS options ----------- ----------------------------------*//** * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */#define LWIP_DNS 0
/* --------------------------------- ---------- UDP options ---------- ---------------------------------*//** * LWIP_UDP==1: Turn on UDP. */#define LWIP_UDP 1
/* --------------------------------- ---------- TCP options ---------- ---------------------------------*//** * LWIP_TCP==1: Turn on TCP. */#define LWIP_TCP 1
#define LWIP_LISTEN_BACKLOG 0
/* ---------------------------------- ---------- Pbuf options ---------- ----------------------------------*//** * PBUF_LINK_HLEN: the number of bytes that should be allocated for a * link level header. The default is 14, the standard value for * Ethernet. */#define PBUF_LINK_HLEN 16
/** * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is * designed to accommodate single full size TCP frame in one pbuf, including * TCP_MSS, IP header, and link header.* */#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)
/* ------------------------------------ ---------- LOOPIF options ---------- ------------------------------------*//** * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c */#define LWIP_HAVE_LOOPIF 0
/* ---------------------------------------------- ---------- Sequential layer options ---------- ----------------------------------------------*/
/** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */#define LWIP_NETCONN 1
/* ------------------------------------ ---------- Socket options ---------- ------------------------------------*//** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */#define LWIP_SOCKET 1
/** * SO_REUSE==1: Enable SO_REUSEADDR */#define SO_REUSE 1
/* ---------------------------------------- ---------- Statistics options ---------- ----------------------------------------*//** * LWIP_STATS==1: Enable statistics collection in lwip_stats. */#define LWIP_STATS 0/* --------------------------------- ---------- PPP options ---------- ---------------------------------*//** * PPP_SUPPORT==1: Enable PPP. */#define PPP_SUPPORT 0


/* --------------------------------------- ---------- Threading options ---------- ---------------------------------------*/
#define LWIP_TCPIP_CORE_LOCKING 0
#if !NO_SYSvoid sys_check_core_locking(void);#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking()#endif
#endif /* LWIP_LWIPOPTS_H */

Perf.c/h

#ifndef LWIP_ARCH_PERF_H#define LWIP_ARCH_PERF_H
#include
struct tms { uint32_t tms_utime; /* user time */ uint32_t tms_stime; /* system time */ uint32_t tms_cutime; /* user time, children */ uint32_t tms_cstime; /* system time, children */};
void perf_times(struct tms *t);void perf_print_times(struct tms *start, struct tms *end, char *key);
//#define PERF 1
#ifdef PERF#define PERF_START struct tms __perf_start;\ struct tms __perf_end; \ perf_times(&__perf_start)#define PERF_STOP(x) perf_times(&__perf_end); \ perf_print_times(&__perf_start, &__perf_end, x);#else /* PERF */#define PERF_START /* null definition */#define PERF_STOP(x) /* null definition */#endif /* PERF */
#endif /* LWIP_ARCH_PERF_H */
#include 
#include "arch/perf.h"
extern uint32_t sys_now(void);void perf_times(struct tms *t){ t->tms_stime = sys_now();}
void perf_print_times(struct tms *start, struct tms *end, char *key){ printf("%s: %lumS\n", key, end->tms_stime - start->tms_stime);}

Portethif.c/f

#ifndef LWIP_ARCH_PERF_H#define LWIP_ARCH_PERF_H
#include
struct tms { uint32_t tms_utime; /* user time */ uint32_t tms_stime; /* system time */ uint32_t tms_cutime; /* user time, children */ uint32_t tms_cstime; /* system time, children */};
void perf_times(struct tms *t);void perf_print_times(struct tms *start, struct tms *end, char *key);
//#define PERF 1
#ifdef PERF#define PERF_START struct tms __perf_start;\ struct tms __perf_end; \ perf_times(&__perf_start)#define PERF_STOP(x) perf_times(&__perf_end); \ perf_print_times(&__perf_start, &__perf_end, x);#else /* PERF */#define PERF_START /* null definition */#define PERF_STOP(x) /* null definition */#endif /* PERF */
#endif /* LWIP_ARCH_PERF_H */
#include 
#include "arch/perf.h"
extern uint32_t sys_now(void);void perf_times(struct tms *t){ t->tms_stime = sys_now();}
void perf_print_times(struct tms *start, struct tms *end, char *key){ printf("%s: %lumS\n", key, end->tms_stime - start->tms_stime);}

系统接口

Lwipopts.h

OSNO_SYS配置为0

#define NO_SYS 0

此时Sys_arch.h/sys_arch.c需要实现以下接口

sys_init

sys_now 获取ms

sys_jiffies获取滴答值

sys_arch_msleep

sys_sem_new

sys_sem_signal

sys_arch_sem_wait

sys_sem_free

LWIP_COMPAT_MUTEX0时实现以下互斥量接口,否则自动使用信号量实现

sys_mutex_new

sys_mutex_lock

sys_mutex_unlock

sys_mutex_free

sys_mbox_new

sys_mbox_post

sys_mbox_trypost

sys_mbox_trypost_fromisr

sys_arch_mbox_fetch

sys_arch_mbox_tryfetch

sys_mbox_free

需要设置消息邮箱的大小

#define DEFAULT_RAW_RECVMBOX_SIZE 10
#define DEFAULT_UDP_RECVMBOX_SIZE 10
#define DEFAULT_TCP_RECVMBOX_SIZE 10
#define TCPIP_MBOX_SIZE 10

sys_thread_new

配置默认线程栈大小和优先级

#define DEFAULT_THREAD_PRIO 7
#define DEFAULT_THREAD_STACKSIZE 1024
#define TCPIP_THREAD_STACKSIZE 1024
#define TCPIP_THREAD_PRIO 7
#define SNMP_STACK_SIZE 1024
#define SNMP_THREAD_PRIO 7
#define SLIPIF_THREAD_STACKSIZE 1024
#define SLIPIF_THREAD_PRIO 7

如果使能LWIP_NETCONN_SEM_PER_THREAD

sys_arch_netconn_sem_get

sys_arch_netconn_sem_alloc

sys_arch_netconn_sem_free

如果使能LWIP_FREERTOS_CHECK_CORE_LOCKING

LWIP_TCPIP_CORE_LOCKING

sys_lock_tcpip_core

sys_unlock_tcpip_core

sys_mark_tcpip_thread

sys_check_core_locking

SYS_LIGHTWEIGHT_PROT使能时

sys_arch_protect

sys_arch_unprotect

错误码处理

Lwipopts.h

#define LWIP_PROVIDE_ERRNO 1

则使用LWIP自己实现的errno.h相关错误码和接口。

互斥量使用

如果有互斥量则

Lwipopts.h

#define LWIP_COMPAT_MUTEX 0

如果定义为1则使用信号量替代互斥量

Sys.h

#define sys_mutex_t                   sys_sem_t
#define sys_mutex_new(mutex) sys_sem_new(mutex, 1)
#define sys_mutex_lock(mutex) sys_sem_wait(mutex)
#define sys_mutex_unlock(mutex) sys_sem_signal(mutex)
#define sys_mutex_free(mutex) sys_sem_free(mutex)
#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex)

LOCK Check

Sys_arch.c

#define LWIP_FREERTOS_CHECK_CORE_LOCKING 1

Lwipopts.h

#define LWIP_TCPIP_CORE_LOCKING 1

堆配置

OS了我们可以直接使用OS提供的堆管理,LWIP的堆和内存池参见前两篇文章分析。

Lwipopts.h

配置内存池memp.c使用堆实现mem_malloc,mem_free

#define MEMP_MEM_MALLOC 1

配置使用系统的堆管理

#define MEM_LIBC_MALLOC 1

此时MEM_USE_POOLS必须为0

实现以下几个接口

mem_clib_free

mem_clib_malloc

mem_clib_calloc

另外就是配置使用内存池的各个组建的内存池大小

MEMP_NUM_xxx

时间

在系统接口中实现

sys_now

sys_jiffies

断言

不定义LWIP_ASSERT

debug.h

#ifndef LWIP_NOASSERT
#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \
LWIP_PLATFORM_ASSERT(message); }} while(0)
#else /* LWIP_NOASSERT */
#define LWIP_ASSERT(message, assertion)
#endif /* LWIP_NOASSERT */

未定义LWIP_PLATFORM_ASSERT

#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
#include
#include
#endif

如果有printf可以cc.h中定义为

#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__);} while(0)

调试

使能配置LWIP_DEBUG

实现LWIP_PLATFORM_DIAG

arch.h中默认是

#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#include
#include
#endif

LWIP_DBG_ON 

LWIP_DBG_TYPES_ON

LWIP_DBG_MASK_LEVEL

三. tcp测试

复制\contrib\apps\tcpecho下的tcpeco.c/h到自己工程中

调用

tcpecho_init

初始化

关键初始化过程

tcpip_init(0,0);

netif_add(&netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &lwip_port_eth_init, ðernet_input);

netif_set_default(&netif);

if (netif_is_link_up(&netif))

{

netif_set_up(&netif);

}

else

{

netif_set_down(&netif);

}

tcpecho_init(); //port 7

PC作为客户端

 

四. tcp性能测试

添加以下代码到自己的工程

src\apps\lwiperf\lwiperf.c

src\include\lwip\apps\lwiperf.h

contrib\examples\lwiperf\lwiperf_example.c/h

端口为lwiperf.h中定义

#define LWIPERF_TCP_PORT_DEFAULT 5001

调用

lwiperf_example_init();

初始化

使用Jperf

PCclient模式

 


评论
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 86浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-12 10:13 34浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 75浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 86浏览
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 85浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 68浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 109浏览
  • 全球知名半导体制造商ROHM Co., Ltd.(以下简称“罗姆”)宣布与Taiwan Semiconductor Manufacturing Company Limited(以下简称“台积公司”)就车载氮化镓功率器件的开发和量产事宜建立战略合作伙伴关系。通过该合作关系,双方将致力于将罗姆的氮化镓器件开发技术与台积公司业界先进的GaN-on-Silicon工艺技术优势结合起来,满足市场对高耐压和高频特性优异的功率元器件日益增长的需求。氮化镓功率器件目前主要被用于AC适配器和服务器电源等消费电子和
    电子资讯报 2024-12-10 17:09 99浏览
  • 应用环境与极具挑战性的测试需求在服务器制造领域里,系统整合测试(System Integration Test;SIT)是确保产品质量和性能的关键步骤。随着服务器系统的复杂性不断提升,包括:多种硬件组件、操作系统、虚拟化平台以及各种应用程序和服务的整合,服务器制造商面临着更有挑战性的测试需求。这些挑战主要体现在以下五个方面:1. 硬件和软件的高度整合:现代服务器通常包括多个处理器、内存模块、储存设备和网络接口。这些硬件组件必须与操作系统及应用软件无缝整合。SIT测试可以帮助制造商确保这些不同组件
    百佳泰测试实验室 2024-12-12 17:45 40浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-12 10:27 49浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 110浏览
  • 全球智能电视时代来临这年头若是消费者想随意地从各个通路中选购电视时,不难发现目前市场上的产品都已是具有智能联网功能的智能电视了,可以宣告智能电视的普及时代已到临!Google从2021年开始大力推广Google TV(即原Android TV的升级版),其他各大品牌商也都跟进推出搭载Google TV操作系统的机种,除了Google TV外,LG、Samsung、Panasonic等大厂牌也开发出自家的智能电视平台,可以看出各家业者都一致地看好这块大饼。智能电视的Wi-Fi连线怎么消失了?智能电
    百佳泰测试实验室 2024-12-12 17:33 46浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 63浏览
  • 近日,搭载紫光展锐W517芯片平台的INMO GO2由影目科技正式推出。作为全球首款专为商务场景设计的智能翻译眼镜,INMO GO2 以“快、准、稳”三大核心优势,突破传统翻译产品局限,为全球商务人士带来高效、自然、稳定的跨语言交流体验。 INMO GO2内置的W517芯片,是紫光展锐4G旗舰级智能穿戴平台,采用四核处理器,具有高性能、低功耗的优势,内置超微高集成技术,采用先进工艺,计算能力相比同档位竞品提升4倍,强大的性能提供更加多样化的应用场景。【视频见P盘链接】 依托“
    紫光展锐 2024-12-11 11:50 72浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦