基于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模式

 


评论
  • 随着全球向绿色能源转型的加速,对高效、可靠和环保元件的需求从未如此强烈。在这种背景下,国产固态继电器(SSR)在实现太阳能逆变器、风力涡轮机和储能系统等关键技术方面发挥着关键作用。本文探讨了绿色能源系统背景下中国固态继电器行业的前景,并强调了2025年的前景。 1.对绿色能源解决方案日益增长的需求绿色能源系统依靠先进的电源管理技术来最大限度地提高效率并最大限度地减少损失。固态继电器以其耐用性、快速开关速度和抗机械磨损而闻名,正日益成为传统机电继电器的首选。可再生能源(尤其是太阳能和风能
    克里雅半导体科技 2025-01-10 16:18 319浏览
  • 根据Global Info Research(环洋市场咨询)项目团队最新调研,预计2030年全球无人机电池和电源产值达到2834百万美元,2024-2030年期间年复合增长率CAGR为10.1%。 无人机电池是为无人机提供动力并使其飞行的关键。无人机使用的电池类型因无人机的大小和型号而异。一些常见的无人机电池类型包括锂聚合物(LiPo)电池、锂离子电池和镍氢(NiMH)电池。锂聚合物电池是最常用的无人机电池类型,因为其能量密度高、设计轻巧。这些电池以输出功率大、飞行时间长而著称。不过,它们需要
    GIRtina 2025-01-13 10:49 163浏览
  • 在不断发展的电子元件领域,继电器——作为切换电路的关键设备,正在经历前所未有的技术变革。固态继电器(SSR)和机械继电器之间的争论由来已久。然而,从未来发展的角度来看,固态继电器正逐渐占据上风。本文将从耐用性、速度和能效三个方面,全面剖析固态继电器为何更具优势,并探讨其在行业中的应用与发展趋势。1. 耐用性:经久耐用的设计机械继电器:机械继电器依靠物理触点完成电路切换。然而,随着时间的推移,这些触点因电弧、氧化和材料老化而逐渐磨损,导致其使用寿命有限。因此,它们更适合低频或对切换耐久性要求不高的
    腾恩科技-彭工 2025-01-10 16:15 97浏览
  • 随着通信技术的迅速发展,现代通信设备需要更高效、可靠且紧凑的解决方案来应对日益复杂的系统。中国自主研发和制造的国产接口芯片,正逐渐成为通信设备(从5G基站到工业通信模块)中的重要基石。这些芯片凭借卓越性能、成本效益及灵活性,满足了现代通信基础设施的多样化需求。 1. 接口芯片在通信设备中的关键作用接口芯片作为数据交互的桥梁,是通信设备中不可或缺的核心组件。它们在设备内的各种子系统之间实现无缝数据传输,支持高速数据交换、协议转换和信号调节等功能。无论是5G基站中的数据处理,还是物联网网关
    克里雅半导体科技 2025-01-10 16:20 432浏览
  • 随着数字化的不断推进,LED显示屏行业对4K、8K等超高清画质的需求日益提升。与此同时,Mini及Micro LED技术的日益成熟,推动了间距小于1.2 Pitch的Mini、Micro LED显示屏的快速发展。这类显示屏不仅画质卓越,而且尺寸适中,通常在110至1000英寸之间,非常适合应用于电影院、监控中心、大型会议、以及电影拍摄等多种室内场景。鉴于室内LED显示屏与用户距离较近,因此对于噪音控制、体积小型化、冗余备份能力及电气安全性的要求尤为严格。为满足这一市场需求,开关电源技术推出了专为
    晶台光耦 2025-01-13 10:42 478浏览
  • 01. 什么是过程能力分析?过程能力研究利用生产过程中初始一批产品的数据,预测制造过程是否能够稳定地生产符合规格的产品。可以把它想象成一种预测。通过历史数据的分析,推断未来是否可以依赖该工艺持续生产高质量产品。客户可能会要求将过程能力研究作为生产件批准程序 (PPAP) 的一部分。这是为了确保制造过程能够持续稳定地生产合格的产品。02. 基本概念在定义制造过程时,目标是确保生产的零件符合上下规格限 (USL 和 LSL)。过程能力衡量制造过程能多大程度上稳定地生产符合规格的产品。核心概念很简单:
    优思学院 2025-01-12 15:43 488浏览
  • 流量传感器是实现对燃气、废气、生活用水、污水、冷却液、石油等各种流体流量精准计量的关键手段。但随着工业自动化、数字化、智能化与低碳化进程的不断加速,采用传统机械式检测方式的流量传感器已不能满足当代流体计量行业对于测量精度、测量范围、使用寿命与维护成本等方面的精细需求。流量传感器的应用场景(部分)超声波流量传感器,是一种利用超声波技术测量流体流量的新型传感器,其主要通过发射超声波信号并接收反射回来的信号,根据超声波在流体中传播的时间、幅度或相位变化等参数,间接计算流体的流量,具有非侵入式测量、高精
    华普微HOPERF 2025-01-13 14:18 457浏览
  • ARMv8-A是ARM公司为满足新需求而重新设计的一个架构,是近20年来ARM架构变动最大的一次。以下是对ARMv8-A的详细介绍: 1. 背景介绍    ARM公司最初并未涉足PC市场,其产品主要针对功耗敏感的移动设备。     随着技术的发展和市场需求的变化,ARM开始扩展到企业设备、服务器等领域,这要求其架构能够支持更大的内存和更复杂的计算任务。 2. 架构特点    ARMv8-A引入了Execution State(执行状
    丙丁先生 2025-01-12 10:30 445浏览
  •   在信号处理过程中,由于信号的时域截断会导致频谱扩展泄露现象。那么导致频谱泄露发生的根本原因是什么?又该采取什么样的改善方法。本文以ADC性能指标的测试场景为例,探讨了对ADC的输出结果进行非周期截断所带来的影响及问题总结。 两个点   为了更好的分析或处理信号,实际应用时需要从频域而非时域的角度观察原信号。但物理意义上只能直接获取信号的时域信息,为了得到信号的频域信息需要利用傅里叶变换这个工具计算出原信号的频谱函数。但对于计算机来说实现这种计算需要面对两个问题: 1.
    TIAN301 2025-01-14 14:15 88浏览
  • 新年伊始,又到了对去年做总结,对今年做展望的时刻 不知道你在2024年初立的Flag都实现了吗? 2025年对自己又有什么新的期待呢? 2024年注定是不平凡的一年, 一年里我测评了50余块开发板, 写出了很多科普文章, 从一个小小的工作室成长为科工公司。 展望2025年, 中国香河英茂科工, 会继续深耕于,具身机器人、飞行器、物联网等方面的研发, 我觉得,要向未来学习未来, 未来是什么? 是掌握在孩子们生活中的发现,和精历, 把最好的技术带给孩子,
    丙丁先生 2025-01-11 11:35 439浏览
  • PNT、GNSS、GPS均是卫星定位和导航相关领域中的常见缩写词,他们经常会被用到,且在很多情况下会被等同使用或替换使用。我们会把定位导航功能测试叫做PNT性能测试,也会叫做GNSS性能测试。我们会把定位导航终端叫做GNSS模块,也会叫做GPS模块。但是实际上他们之间是有一些重要的区别。伴随着技术发展与越发深入,我们有必要对这三个词汇做以清晰的区分。一、什么是GPS?GPS是Global Positioning System(全球定位系统)的缩写,它是美国建立的全球卫星定位导航系统,是GNSS概
    德思特测试测量 2025-01-13 15:42 458浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦