Compare commits
27 Commits
Author | SHA1 | Date |
---|---|---|
xiangbingj | e5068a1461 | |
xiangbingj | 0a1e683246 | |
xiangbingj | 5a1547b5fe | |
xiangbingj | 63c0f4f6b2 | |
xiangbingj | ab3add683d | |
xiangbingj | 49162e6a25 | |
xiangbingj | ff471f9c48 | |
xiangbingj | 2731838f6a | |
xiangbingj | 5a60ed309c | |
xiangbingj | ff1c64a399 | |
xiangbingj | dc22624775 | |
xiangbingj | 1098761fcb | |
xiangbingj | 6811374760 | |
xiangbingj | 429fe3eb13 | |
xiangbingj | 7b6a7f474b | |
xiangbingj | 0d717ea4e4 | |
xiangbingj | c47f06ee68 | |
xiangbingj | 5d95db9f17 | |
xiangbingj | 365650efdf | |
xiangbingj | ee89ad7790 | |
xiangbingj | 0f54ad2ed1 | |
xiangbingj | c89f9afefc | |
xiangbingj | 71ae0af518 | |
xiangbingj | 97f550299f | |
xiangbingj | 7ed85b3cd4 | |
xiangbingj | 2d295c3619 | |
xiangbingj | 53a011fa55 |
|
@ -71,6 +71,7 @@ SECTIONS
|
|||
PROVIDE( _text = ABSOLUTE(.) );
|
||||
/* Initialization code segment */
|
||||
KEEP( *(.text.start) )
|
||||
KEEP( *(.text.systick) )
|
||||
*(.text.unlikely .text.unlikely.*)
|
||||
*(.text.startup .text.startup.*)
|
||||
/* Normal code segment */
|
||||
|
@ -113,7 +114,7 @@ SECTIONS
|
|||
{
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)
|
||||
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
} >ram AT>ram :ram_ro
|
||||
|
||||
|
@ -256,6 +257,7 @@ SECTIONS
|
|||
PROVIDE( _sp1 = _tp1 + _stack_size );
|
||||
|
||||
/* Heap end is at the end of memory, the memory size can set in kconfig */
|
||||
PROVIDE( _heap_end = _ram_end );
|
||||
PROVIDE( _heap_end = _ram_end);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,36 @@ _start:
|
|||
.type trap_entry, @function
|
||||
.align 2
|
||||
trap_entry:
|
||||
addi sp, sp, -REGBYTES
|
||||
sd t0, 0x0(sp)
|
||||
csrr t0, mcause
|
||||
bgez t0, .handle_other
|
||||
# Test soft interrupt
|
||||
slli t0, t0, 1
|
||||
addi t0, t0, -(IRQ_M_SOFT << 1)
|
||||
bnez t0, .handle_other
|
||||
# Interupt is soft interrupt
|
||||
# Get event
|
||||
addi sp, sp, -REGBYTES
|
||||
sd t1, 0x0(sp)
|
||||
la t0, g_core_pending_switch
|
||||
csrr t1, mhartid
|
||||
slli t1, t1, 3
|
||||
add t0, t0, t1
|
||||
ld t1, 0x0(sp)
|
||||
addi sp, sp, REGBYTES
|
||||
# Test ContextSwitch event
|
||||
ld t0, 0x0(t0)
|
||||
beqz t0, .handle_other
|
||||
|
||||
ld t0, 0x0(sp)
|
||||
addi sp, sp, REGBYTES
|
||||
# Do not use jal here
|
||||
j xPortSysTickInt
|
||||
mret
|
||||
.handle_other:
|
||||
ld t0, 0x0(sp)
|
||||
addi sp, sp, REGBYTES
|
||||
addi sp, sp, -64*REGBYTES
|
||||
|
||||
SREG x1, 1*REGBYTES(sp)
|
||||
|
|
|
@ -110,7 +110,3 @@ void _init_bsp(int core_id, int number_of_cores)
|
|||
exit(ret);
|
||||
}
|
||||
|
||||
int pthread_setcancelstate(int __state, int *__oldstate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -97,6 +97,8 @@ static const char *TAG = "SYSCALL";
|
|||
extern char _heap_start[];
|
||||
extern char _heap_end[];
|
||||
char *_heap_cur = &_heap_start[0];
|
||||
char *_heap_line = &_heap_start[0];
|
||||
char *_ioheap_line = &_heap_end[0]-0x40000000;
|
||||
|
||||
sys_putchar_t sys_putchar;
|
||||
sys_getchar_t sys_getchar;
|
||||
|
@ -184,6 +186,14 @@ static size_t sys_brk(size_t pos)
|
|||
res = -ENOMEM;
|
||||
} else
|
||||
{
|
||||
if((uintptr_t)pos > (uintptr_t)_heap_line)
|
||||
{
|
||||
_heap_line = (char *)(uintptr_t)pos;
|
||||
if((uintptr_t)_heap_line-0x40000000 > (uintptr_t)_ioheap_line)
|
||||
{
|
||||
LOGE(TAG, "WARNING: cache heap line > iomem heap line!\r\n");
|
||||
}
|
||||
}
|
||||
/* Adjust brk pointer. */
|
||||
_heap_cur = (char *)(uintptr_t)pos;
|
||||
/* Return current address. */
|
||||
|
|
|
@ -217,43 +217,3 @@ int clint_ipi_unregister(void)
|
|||
return clint_ipi_register(NULL, NULL);
|
||||
}
|
||||
|
||||
uintptr_t handle_irq_m_timer(uintptr_t cause, uintptr_t epc)
|
||||
{
|
||||
/* Read core id */
|
||||
uint64_t core_id = current_coreid();
|
||||
uint64_t ie_flag = read_csr(mie);
|
||||
|
||||
clear_csr(mie, MIP_MTIP | MIP_MSIP);
|
||||
set_csr(mstatus, MSTATUS_MIE);
|
||||
if(clint_timer_instance[core_id].callback != NULL)
|
||||
clint_timer_instance[core_id].callback(
|
||||
clint_timer_instance[core_id].ctx);
|
||||
clear_csr(mstatus, MSTATUS_MIE);
|
||||
set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
|
||||
write_csr(mie, ie_flag);
|
||||
/* If not single shot and cycle interval is not 0, repeat this timer */
|
||||
if(!clint_timer_instance[core_id].single_shot && clint_timer_instance[core_id].cycles != 0)
|
||||
{
|
||||
/* Set mtimecmp by core id */
|
||||
clint->mtimecmp[core_id] += clint_timer_instance[core_id].cycles;
|
||||
} else
|
||||
clear_csr(mie, MIP_MTIP);
|
||||
return epc;
|
||||
}
|
||||
|
||||
uintptr_t handle_irq_m_soft(uintptr_t cause, uintptr_t epc)
|
||||
{
|
||||
/* Read core id */
|
||||
uint64_t core_id = current_coreid();
|
||||
/* Clear the Machine-Software bit in MIE to prevent call again */
|
||||
clear_csr(mie, MIP_MSIP);
|
||||
set_csr(mstatus, MSTATUS_MIE);
|
||||
/* Clear ipi flag */
|
||||
clint_ipi_clear(core_id);
|
||||
if(clint_ipi_instance[core_id].callback != NULL)
|
||||
clint_ipi_instance[core_id].callback(clint_ipi_instance[core_id].ctx);
|
||||
clear_csr(mstatus, MSTATUS_MIE);
|
||||
set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
|
||||
set_csr(mie, MIP_MSIP);
|
||||
return epc;
|
||||
}
|
||||
|
|
|
@ -15,18 +15,27 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dmac.h"
|
||||
#include "fpioa.h"
|
||||
#include "plic.h"
|
||||
#include "stdlib.h"
|
||||
#include "sysctl.h"
|
||||
#include "utils.h"
|
||||
#include "iomem.h"
|
||||
|
||||
volatile dmac_t *const dmac = (dmac_t *)DMAC_BASE_ADDR;
|
||||
|
||||
typedef struct _dmac_context
|
||||
{
|
||||
dmac_channel_number_t dmac_channel;
|
||||
#if FIX_CACHE
|
||||
uint8_t *dest_buffer;
|
||||
uint8_t *src_malloc;
|
||||
uint8_t *dest_malloc;
|
||||
size_t buf_len;
|
||||
#endif
|
||||
|
||||
plic_irq_callback_t callback;
|
||||
void *ctx;
|
||||
} dmac_context_t;
|
||||
|
@ -269,7 +278,7 @@ void dmac_disable_channel_interrupt(dmac_channel_number_t channel_num)
|
|||
writeq(0, &dmac->channel[channel_num].intstatus_en);
|
||||
}
|
||||
|
||||
static void dmac_chanel_interrupt_clear(dmac_channel_number_t channel_num)
|
||||
static void dmac_channel_interrupt_clear(dmac_channel_number_t channel_num)
|
||||
{
|
||||
writeq(0xffffffff, &dmac->channel[channel_num].intclear);
|
||||
}
|
||||
|
@ -353,6 +362,40 @@ int dmac_set_channel_param(dmac_channel_number_t channel_num,
|
|||
dmac_ch_ctl_u_t ctl;
|
||||
dmac_ch_cfg_u_t cfg_u;
|
||||
|
||||
#if FIX_CACHE
|
||||
uint8_t *src_io = (uint8_t *)src;
|
||||
uint8_t *dest_io = (uint8_t *)dest;
|
||||
if(is_memory_cache((uintptr_t)src))
|
||||
{
|
||||
if(src_inc == DMAC_ADDR_NOCHANGE)
|
||||
{
|
||||
src_io = (uint8_t *)iomem_malloc(1<<dmac_trans_width);
|
||||
memcpy(src_io, src, 1<<dmac_trans_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
src_io = (uint8_t *)iomem_malloc(blockSize * (1<<dmac_trans_width));
|
||||
memcpy(src_io, src, blockSize * (1<<dmac_trans_width));
|
||||
}
|
||||
dmac_context[channel_num].src_malloc = src_io;
|
||||
}
|
||||
if(is_memory_cache((uintptr_t)dest))
|
||||
{
|
||||
if(dest_inc == DMAC_ADDR_NOCHANGE)
|
||||
{
|
||||
dest_io = (uint8_t *)iomem_malloc(1<<dmac_trans_width);
|
||||
dmac_context[channel_num].buf_len = 1<<dmac_trans_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest_io = (uint8_t *)iomem_malloc(blockSize * (1<<dmac_trans_width));
|
||||
dmac_context[channel_num].buf_len = blockSize * (1<<dmac_trans_width);
|
||||
}
|
||||
dmac_context[channel_num].dest_malloc = dest_io;
|
||||
dmac_context[channel_num].dest_buffer = dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest);
|
||||
dmac_transfer_flow_t flow_control;
|
||||
if(mem_type_src == 0 && mem_type_dest == 0)
|
||||
|
@ -381,8 +424,13 @@ int dmac_set_channel_param(dmac_channel_number_t channel_num,
|
|||
|
||||
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
|
||||
|
||||
#if FIX_CACHE
|
||||
dmac->channel[channel_num].sar = (uint64_t)src_io;
|
||||
dmac->channel[channel_num].dar = (uint64_t)dest_io;
|
||||
#else
|
||||
dmac->channel[channel_num].sar = (uint64_t)src;
|
||||
dmac->channel[channel_num].dar = (uint64_t)dest;
|
||||
#endif
|
||||
|
||||
ctl.data = readq(&dmac->channel[channel_num].ctl);
|
||||
ctl.ch_ctl.sms = DMAC_MASTER1;
|
||||
|
@ -716,7 +764,7 @@ void dmac_set_single_mode(dmac_channel_number_t channel_num,
|
|||
dmac_transfer_width_t dmac_trans_width,
|
||||
size_t block_size)
|
||||
{
|
||||
dmac_chanel_interrupt_clear(channel_num);
|
||||
dmac_channel_interrupt_clear(channel_num);
|
||||
dmac_channel_disable(channel_num);
|
||||
dmac_wait_idle(channel_num);
|
||||
dmac_set_channel_param(channel_num, src, dest, src_inc, dest_inc,
|
||||
|
@ -736,6 +784,22 @@ int dmac_is_done(dmac_channel_number_t channel_num)
|
|||
void dmac_wait_done(dmac_channel_number_t channel_num)
|
||||
{
|
||||
dmac_wait_idle(channel_num);
|
||||
#if FIX_CACHE
|
||||
if(dmac_context[channel_num].dest_buffer)
|
||||
{
|
||||
memcpy(dmac_context[channel_num].dest_buffer, dmac_context[channel_num].dest_malloc, dmac_context[channel_num].buf_len);
|
||||
|
||||
iomem_free(dmac_context[channel_num].dest_malloc);
|
||||
dmac_context[channel_num].dest_malloc = NULL;
|
||||
dmac_context[channel_num].dest_buffer = NULL;
|
||||
dmac_context[channel_num].buf_len = 0;
|
||||
}
|
||||
if(dmac_context[channel_num].src_malloc)
|
||||
{
|
||||
iomem_free(dmac_context[channel_num].src_malloc);
|
||||
dmac_context[channel_num].src_malloc = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int dmac_is_idle(dmac_channel_number_t channel_num)
|
||||
|
@ -752,7 +816,7 @@ void dmac_wait_idle(dmac_channel_number_t channel_num)
|
|||
{
|
||||
while(!dmac_is_idle(channel_num))
|
||||
;
|
||||
dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */
|
||||
dmac_channel_interrupt_clear(channel_num); /* clear interrupt */
|
||||
}
|
||||
|
||||
void dmac_set_src_dest_length(dmac_channel_number_t channel_num, const void *src, void *dest, size_t len)
|
||||
|
@ -770,7 +834,23 @@ static int dmac_irq_callback(void *ctx)
|
|||
{
|
||||
dmac_context_t *v_dmac_context = (dmac_context_t *)(ctx);
|
||||
dmac_channel_number_t v_dmac_channel = v_dmac_context->dmac_channel;
|
||||
dmac_chanel_interrupt_clear(v_dmac_channel);
|
||||
dmac_channel_interrupt_clear(v_dmac_channel);
|
||||
#if FIX_CACHE
|
||||
if(v_dmac_context->dest_buffer)
|
||||
{
|
||||
memcpy(v_dmac_context->dest_buffer, v_dmac_context->dest_malloc, v_dmac_context->buf_len);
|
||||
iomem_free(v_dmac_context->dest_malloc);
|
||||
v_dmac_context->dest_malloc = NULL;
|
||||
v_dmac_context->dest_buffer = NULL;
|
||||
v_dmac_context->buf_len = 0;
|
||||
}
|
||||
if(v_dmac_context->src_malloc)
|
||||
{
|
||||
iomem_free(v_dmac_context->src_malloc);
|
||||
v_dmac_context->src_malloc = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(v_dmac_context->callback != NULL)
|
||||
v_dmac_context->callback(v_dmac_context->ctx);
|
||||
|
||||
|
|
|
@ -201,6 +201,11 @@ void dvp_set_image_size(uint32_t width, uint32_t height)
|
|||
|
||||
void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
configASSERT(!is_memory_cache((uintptr_t)r_addr));
|
||||
configASSERT(!is_memory_cache((uintptr_t)g_addr));
|
||||
configASSERT(!is_memory_cache((uintptr_t)b_addr));
|
||||
#endif
|
||||
dvp->r_addr = r_addr;
|
||||
dvp->g_addr = g_addr;
|
||||
dvp->b_addr = b_addr;
|
||||
|
@ -208,6 +213,9 @@ void dvp_set_ai_addr(uint32_t r_addr, uint32_t g_addr, uint32_t b_addr)
|
|||
|
||||
void dvp_set_display_addr(uint32_t addr)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
configASSERT(!is_memory_cache((uintptr_t)addr));
|
||||
#endif
|
||||
dvp->rgb_addr = addr;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "string.h"
|
||||
#include "sysctl.h"
|
||||
#include "utils.h"
|
||||
#include "iomem.h"
|
||||
|
||||
typedef struct _i2c_slave_instance
|
||||
{
|
||||
|
@ -167,7 +168,11 @@ void i2c_send_data_dma(dmac_channel_number_t dma_channel_num, i2c_device_number_
|
|||
configASSERT(i2c_num < I2C_MAX_NUM);
|
||||
volatile i2c_t *i2c_adapter = i2c[i2c_num];
|
||||
i2c_adapter->clr_tx_abrt = i2c_adapter->clr_tx_abrt;
|
||||
#if FIX_CACHE
|
||||
uint32_t *buf = iomem_malloc(send_buf_len * sizeof(uint32_t));
|
||||
#else
|
||||
uint32_t *buf = malloc(send_buf_len * sizeof(uint32_t));
|
||||
#endif
|
||||
int i;
|
||||
for(i = 0; i < send_buf_len; i++)
|
||||
{
|
||||
|
@ -179,7 +184,11 @@ void i2c_send_data_dma(dmac_channel_number_t dma_channel_num, i2c_device_number_
|
|||
DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, send_buf_len);
|
||||
|
||||
dmac_wait_done(dma_channel_num);
|
||||
#if FIX_CACHE
|
||||
iomem_free((void *)buf);
|
||||
#else
|
||||
free((void *)buf);
|
||||
#endif
|
||||
|
||||
while((i2c_adapter->status & I2C_STATUS_ACTIVITY) || !(i2c_adapter->status & I2C_STATUS_TFE))
|
||||
{
|
||||
|
@ -233,8 +242,11 @@ void i2c_recv_data_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_
|
|||
configASSERT(i2c_num < I2C_MAX_NUM);
|
||||
|
||||
volatile i2c_t *i2c_adapter = i2c[i2c_num];
|
||||
|
||||
#if FIX_CACHE
|
||||
uint32_t *write_cmd = iomem_malloc(sizeof(uint32_t) * (send_buf_len + receive_buf_len));
|
||||
#else
|
||||
uint32_t *write_cmd = malloc(sizeof(uint32_t) * (send_buf_len + receive_buf_len));
|
||||
#endif
|
||||
size_t i;
|
||||
for(i = 0; i < send_buf_len; i++)
|
||||
write_cmd[i] = *send_buf++;
|
||||
|
@ -257,8 +269,11 @@ void i2c_recv_data_dma(dmac_channel_number_t dma_send_channel_num, dmac_channel_
|
|||
{
|
||||
receive_buf[i] = (uint8_t)write_cmd[i];
|
||||
}
|
||||
|
||||
free(write_cmd);
|
||||
#if FIX_CACHE
|
||||
iomem_free(write_cmd);
|
||||
#else
|
||||
free(write_cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int i2c_dma_irq(void *ctx)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _IOMEM_MALLOC_H
|
||||
#define _IOMEM_MALLOC_H
|
||||
|
||||
void iomem_free(void *paddr) ;
|
||||
void *iomem_malloc(uint32_t size);
|
||||
uint32_t iomem_unused();
|
||||
|
||||
#endif
|
|
@ -33,6 +33,8 @@ extern "C" {
|
|||
#define KENDRYTE_MIN(a, b) ((a) > (b) ? (b) : (a))
|
||||
#define KENDRYTE_MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define FIX_CACHE 1
|
||||
|
||||
#ifdef __ASSEMBLY__
|
||||
#define KENDRYTE_CAST(type, ptr) ptr
|
||||
#else /* __ASSEMBLY__ */
|
||||
|
@ -340,6 +342,7 @@ uint32_t get_bit(volatile uint32_t *bits, uint32_t mask, size_t offset);
|
|||
*/
|
||||
uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset);
|
||||
|
||||
uint32_t is_memory_cache(uintptr_t address);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "iomem.h"
|
||||
#include "printf.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#define IOMEM_BLOCK_SIZE 256
|
||||
|
||||
typedef struct _iomem_malloc_t
|
||||
{
|
||||
void (*init)();
|
||||
uint32_t (*unused)();
|
||||
uint8_t *membase;
|
||||
uint32_t memsize;
|
||||
uint32_t memtblsize;
|
||||
uint16_t *memmap;
|
||||
uint8_t memrdy;
|
||||
} iomem_malloc_t;
|
||||
|
||||
static void iomem_init();
|
||||
static uint32_t k_unused();
|
||||
extern char *_ioheap_line;
|
||||
extern char *_heap_line;
|
||||
extern char _heap_start[];
|
||||
extern char *_heap_cur;
|
||||
|
||||
iomem_malloc_t malloc_cortol =
|
||||
{
|
||||
iomem_init,
|
||||
k_unused,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0
|
||||
};
|
||||
|
||||
static void iomem_set(void *s, uint8_t c, uint32_t num)
|
||||
{
|
||||
uint8_t *xs = s;
|
||||
while(num--)
|
||||
*xs++=c;
|
||||
}
|
||||
|
||||
static void iomem_init()
|
||||
{
|
||||
malloc_cortol.membase = (uint8_t *)((uintptr_t)_heap_line-0x40000000);
|
||||
malloc_cortol.memsize = (uint32_t)_ioheap_line - (uint32_t)malloc_cortol.membase;
|
||||
|
||||
malloc_cortol.memtblsize = malloc_cortol.memsize / IOMEM_BLOCK_SIZE;
|
||||
malloc_cortol.memmap = (uint16_t *)malloc(malloc_cortol.memtblsize * 2);
|
||||
mb();
|
||||
|
||||
malloc_cortol.membase = (uint8_t *)((uintptr_t)_heap_line-0x40000000);
|
||||
malloc_cortol.memsize = (uint32_t)_ioheap_line - (uint32_t)malloc_cortol.membase;
|
||||
malloc_cortol.memtblsize = malloc_cortol.memsize / IOMEM_BLOCK_SIZE;
|
||||
|
||||
iomem_set(malloc_cortol.memmap, 0, malloc_cortol.memtblsize * 2);
|
||||
iomem_set(malloc_cortol.membase, 0, malloc_cortol.memsize);
|
||||
malloc_cortol.memrdy = 1;
|
||||
}
|
||||
|
||||
static uint32_t k_unused()
|
||||
{
|
||||
uint32_t unused=0;
|
||||
unused = (uintptr_t)_ioheap_line + 0x40000000 - (uintptr_t)_heap_line;
|
||||
|
||||
return unused;
|
||||
}
|
||||
|
||||
static uint32_t k_malloc(uint32_t size)
|
||||
{
|
||||
signed long offset = 0;
|
||||
uint32_t xmemb;
|
||||
uint32_t kmemb = 0;
|
||||
|
||||
if(!malloc_cortol.memrdy)
|
||||
malloc_cortol.init();
|
||||
if(size==0)
|
||||
return 0XFFFFFFFF;
|
||||
xmemb=size / IOMEM_BLOCK_SIZE;
|
||||
if(size % IOMEM_BLOCK_SIZE)
|
||||
xmemb++;
|
||||
for(offset=malloc_cortol.memtblsize-1; offset>=0; offset--)
|
||||
{
|
||||
if(!malloc_cortol.memmap[offset])
|
||||
{
|
||||
kmemb++;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = offset - malloc_cortol.memmap[offset] + 1;
|
||||
kmemb=0;
|
||||
}
|
||||
if(kmemb==xmemb)
|
||||
{
|
||||
malloc_cortol.memmap[offset] = xmemb;
|
||||
malloc_cortol.memmap[offset+xmemb-1] = xmemb;
|
||||
return (offset * IOMEM_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
return 0XFFFFFFFF;
|
||||
}
|
||||
|
||||
static uint8_t k_free(uint32_t offset)
|
||||
{
|
||||
if(!malloc_cortol.memrdy)
|
||||
{
|
||||
malloc_cortol.init();
|
||||
return 1;
|
||||
}
|
||||
if(offset < malloc_cortol.memsize)
|
||||
{
|
||||
int index=offset / IOMEM_BLOCK_SIZE;
|
||||
int nmemb=malloc_cortol.memmap[index];
|
||||
|
||||
malloc_cortol.memmap[index] = 0;
|
||||
malloc_cortol.memmap[index+nmemb-1] = 0;
|
||||
|
||||
if((uintptr_t)_ioheap_line == (uintptr_t)malloc_cortol.membase + offset)
|
||||
{
|
||||
_ioheap_line = (char *)((uintptr_t)_ioheap_line + nmemb * IOMEM_BLOCK_SIZE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
void iomem_free(void *paddr)
|
||||
{
|
||||
uint32_t offset;
|
||||
if(paddr == NULL)
|
||||
return;
|
||||
offset=(uintptr_t)paddr - (uintptr_t)malloc_cortol.membase;
|
||||
k_free(offset);
|
||||
}
|
||||
|
||||
void *iomem_malloc(uint32_t size)
|
||||
{
|
||||
uint32_t offset;
|
||||
offset=k_malloc(size);
|
||||
if(offset == 0XFFFFFFFF)
|
||||
{
|
||||
printk("IOMEM malloc OUT of MEMORY!\r\n");
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if((uintptr_t)_ioheap_line > (uintptr_t)malloc_cortol.membase + offset)
|
||||
{
|
||||
_ioheap_line = (char *)((uintptr_t)malloc_cortol.membase + offset);
|
||||
if((uintptr_t)_ioheap_line < (uintptr_t)_heap_line-0x40000000)
|
||||
{
|
||||
printk("WARNING: iomem heap line < cache heap line!\r\n");
|
||||
}
|
||||
};
|
||||
|
||||
return (void*)((uintptr_t)malloc_cortol.membase + offset);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t iomem_unused()
|
||||
{
|
||||
return malloc_cortol.unused();
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@
|
|||
#include "dmac.h"
|
||||
#include "kpu.h"
|
||||
#include "printf.h"
|
||||
#include "nncase.h"
|
||||
//#include "nncase.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define LAYER_BURST_SIZE 12
|
||||
|
||||
|
@ -1004,8 +1005,13 @@ static void kpu_quantize(const kpu_model_quantize_layer_argument_t *arg, kpu_mod
|
|||
{
|
||||
size_t count = arg->count;
|
||||
const float *src = (const float *)(ctx->main_buffer + arg->main_mem_in_address);
|
||||
;
|
||||
const kpu_model_quant_param_t q = arg->quant_param;
|
||||
|
||||
kpu_model_quant_param_t q;
|
||||
#if FIX_CACHE
|
||||
memcpy(&q, &arg->quant_param, sizeof(kpu_model_quant_param_t));
|
||||
#else
|
||||
q = arg->quant_param;
|
||||
#endif
|
||||
float scale = 1.f / q.scale;
|
||||
|
||||
uint8_t *dest = (uint8_t *)(ctx->main_buffer + arg->mem_out_address);
|
||||
|
@ -1026,8 +1032,12 @@ static void kpu_kmodel_dequantize(const kpu_model_dequantize_layer_argument_t *a
|
|||
const uint8_t *src = (const uint8_t *)(ctx->main_buffer + arg->main_mem_in_address);
|
||||
float *dest = (float *)(ctx->main_buffer + arg->main_mem_out_address);
|
||||
size_t oc, count = arg->count;
|
||||
const kpu_model_quant_param_t q = arg->quant_param;
|
||||
|
||||
kpu_model_quant_param_t q;
|
||||
#if FIX_CACHE
|
||||
memcpy(&q, &arg->quant_param, sizeof(kpu_model_quant_param_t));
|
||||
#else
|
||||
q = arg->quant_param;
|
||||
#endif
|
||||
for(oc = 0; oc < count; oc++)
|
||||
dest[oc] = *src++ * q.scale + q.bias;
|
||||
}
|
||||
|
@ -1132,7 +1142,10 @@ static void kpu_kmodel_fully_connected(const kpu_model_fully_connected_layer_arg
|
|||
const float *src = (const float *)(ctx->main_buffer + arg->main_mem_in_address);
|
||||
float *dest = (float *)(ctx->main_buffer + arg->main_mem_out_address);
|
||||
uint32_t in_channels = arg->in_channels, out_channels = arg->out_channels, ic, oc;
|
||||
const float *weights = arg->weights, *bias = arg->weights + in_channels * out_channels;
|
||||
float *weights = (float *)malloc(in_channels * out_channels * sizeof(float));
|
||||
float *bias = (float *)malloc(out_channels * sizeof(float));
|
||||
memcpy(weights, arg->weights, out_channels * in_channels * sizeof(float));
|
||||
memcpy(bias, arg->weights + in_channels * out_channels, out_channels * sizeof(float));
|
||||
|
||||
if(in_channels % 8 == 0)
|
||||
{
|
||||
|
@ -1179,7 +1192,8 @@ static void kpu_kmodel_fully_connected(const kpu_model_fully_connected_layer_arg
|
|||
dest[oc] = sum + bias[oc];
|
||||
}
|
||||
}
|
||||
|
||||
free(weights);
|
||||
free(bias);
|
||||
kpu_float_activation(dest, out_channels, arg->act);
|
||||
}
|
||||
|
||||
|
@ -1357,6 +1371,9 @@ static void kpu_upload(const kpu_model_upload_layer_argument_t *arg, kpu_model_c
|
|||
|
||||
int kpu_load_kmodel(kpu_model_context_t *ctx, const uint8_t *buffer)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
configASSERT(!is_memory_cache((uintptr_t)buffer));
|
||||
#endif
|
||||
uintptr_t base_addr = (uintptr_t)buffer;
|
||||
const kpu_kmodel_header_t *header = (const kpu_kmodel_header_t *)buffer;
|
||||
|
||||
|
@ -1374,7 +1391,7 @@ int kpu_load_kmodel(kpu_model_context_t *ctx, const uint8_t *buffer)
|
|||
return -1;
|
||||
} else if(header->version == 'KMDL')
|
||||
{
|
||||
return nncase_load_kmodel(ctx, buffer);
|
||||
;//return nncase_load_kmodel(ctx, buffer_iomem);
|
||||
} else
|
||||
{
|
||||
return -1;
|
||||
|
@ -1385,8 +1402,8 @@ int kpu_load_kmodel(kpu_model_context_t *ctx, const uint8_t *buffer)
|
|||
|
||||
int kpu_get_output(kpu_model_context_t *ctx, uint32_t index, uint8_t **data, size_t *size)
|
||||
{
|
||||
if(ctx->is_nncase)
|
||||
return nncase_get_output(ctx, index, data, size);
|
||||
//if(ctx->is_nncase)
|
||||
// return nncase_get_output(ctx, index, data, size);
|
||||
|
||||
if(index >= ctx->output_count)
|
||||
return -1;
|
||||
|
@ -1399,8 +1416,8 @@ int kpu_get_output(kpu_model_context_t *ctx, uint32_t index, uint8_t **data, siz
|
|||
|
||||
void kpu_model_free(kpu_model_context_t *ctx)
|
||||
{
|
||||
if(ctx->is_nncase)
|
||||
return nncase_model_free(ctx);
|
||||
//if(ctx->is_nncase)
|
||||
// return nncase_model_free(ctx);
|
||||
|
||||
free(ctx->main_buffer);
|
||||
ctx->main_buffer = NULL;
|
||||
|
@ -1606,8 +1623,8 @@ static void ai_step_not_isr(void *userdata)
|
|||
|
||||
int kpu_run_kmodel(kpu_model_context_t *ctx, const uint8_t *src, dmac_channel_number_t dma_ch, kpu_done_callback_t done_callback, void *userdata)
|
||||
{
|
||||
if(ctx->is_nncase)
|
||||
return nncase_run_kmodel(ctx, src, dma_ch, done_callback, userdata);
|
||||
//if(ctx->is_nncase)
|
||||
// return nncase_run_kmodel(ctx, src, dma_ch, done_callback, userdata);
|
||||
|
||||
ctx->dma_ch = dma_ch;
|
||||
ctx->done_callback = done_callback;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "spi.h"
|
||||
#include "sysctl.h"
|
||||
#include "utils.h"
|
||||
#include "iomem.h"
|
||||
|
||||
volatile spi_t *const spi[4] =
|
||||
{
|
||||
|
@ -411,7 +412,11 @@ void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_
|
|||
switch(spi_transfer_width)
|
||||
{
|
||||
case SPI_TRANS_SHORT:
|
||||
buf = malloc((tx_len) * sizeof(uint32_t));
|
||||
#if FIX_CACHE
|
||||
buf = (uint32_t *)iomem_malloc((tx_len) * sizeof(uint32_t));
|
||||
#else
|
||||
buf = (uint32_t *)malloc((tx_len) * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < tx_len; i++)
|
||||
buf[i] = ((uint16_t *)tx_buff)[i];
|
||||
break;
|
||||
|
@ -420,7 +425,12 @@ void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_
|
|||
break;
|
||||
case SPI_TRANS_CHAR:
|
||||
default:
|
||||
buf = malloc((tx_len) * sizeof(uint32_t));
|
||||
#if FIX_CACHE
|
||||
buf = (uint32_t *)iomem_malloc((tx_len) * sizeof(uint32_t));
|
||||
#else
|
||||
buf = (uint32_t *)malloc((tx_len) * sizeof(uint32_t));
|
||||
#endif
|
||||
|
||||
for(i = 0; i < tx_len; i++)
|
||||
buf[i] = ((uint8_t *)tx_buff)[i];
|
||||
break;
|
||||
|
@ -429,13 +439,19 @@ void spi_send_data_normal_dma(dmac_channel_number_t channel_num, spi_device_num_
|
|||
spi_handle->ssienr = 0x01;
|
||||
|
||||
sysctl_dma_select((sysctl_dma_channel_t)channel_num, SYSCTL_DMA_SELECT_SSI0_TX_REQ + spi_num * 2);
|
||||
|
||||
dmac_set_single_mode(channel_num, buf, (void *)(&spi_handle->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
|
||||
DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, tx_len);
|
||||
spi_handle->ser = 1U << chip_select;
|
||||
dmac_wait_done(channel_num);
|
||||
if(spi_transfer_width != SPI_TRANS_INT)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
iomem_free((void *)buf);
|
||||
#else
|
||||
free((void *)buf);
|
||||
|
||||
#endif
|
||||
}
|
||||
while((spi_handle->sr & 0x05) != 0x04)
|
||||
;
|
||||
spi_handle->ser = 0x00;
|
||||
|
@ -472,8 +488,13 @@ void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
|
||||
size_t v_max_len = v_tx_len > v_rx_len ? v_tx_len : v_rx_len;
|
||||
|
||||
#if FIX_CACHE
|
||||
uint32_t *v_tx_buf = iomem_malloc(v_max_len * 4);
|
||||
uint32_t *v_rx_buf = iomem_malloc(v_max_len * 4);
|
||||
#else
|
||||
uint32_t *v_tx_buf = malloc(v_max_len * 4);
|
||||
uint32_t *v_rx_buf = malloc(v_max_len * 4);
|
||||
#endif
|
||||
uint32_t i = 0;
|
||||
switch(frame_width)
|
||||
{
|
||||
|
@ -552,8 +573,13 @@ void spi_dup_send_receive_data_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
rx_buf[i] = v_rx_buf[i];
|
||||
break;
|
||||
}
|
||||
#if FIX_CACHE
|
||||
iomem_free(v_tx_buf);
|
||||
iomem_free(v_rx_buf);
|
||||
#else
|
||||
free(v_tx_buf);
|
||||
free(v_rx_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_receive_data_standard(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint8_t *cmd_buff,
|
||||
|
@ -721,7 +747,11 @@ void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
switch(frame_width)
|
||||
{
|
||||
case SPI_TRANS_INT:
|
||||
#if FIX_CACHE
|
||||
write_cmd = iomem_malloc(cmd_len + rx_len);
|
||||
#else
|
||||
write_cmd = malloc(cmd_len + rx_len);
|
||||
#endif
|
||||
for(i = 0; i < cmd_len / 4; i++)
|
||||
write_cmd[i] = ((uint32_t *)cmd_buff)[i];
|
||||
read_buf = &write_cmd[i];
|
||||
|
@ -729,7 +759,11 @@ void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
v_cmd_len = cmd_len / 4;
|
||||
break;
|
||||
case SPI_TRANS_SHORT:
|
||||
#if FIX_CACHE
|
||||
write_cmd = iomem_malloc((cmd_len + rx_len) / 2 * sizeof(uint32_t));
|
||||
#else
|
||||
write_cmd = malloc((cmd_len + rx_len) / 2 * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < cmd_len / 2; i++)
|
||||
write_cmd[i] = ((uint16_t *)cmd_buff)[i];
|
||||
read_buf = &write_cmd[i];
|
||||
|
@ -737,7 +771,11 @@ void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
v_cmd_len = cmd_len / 2;
|
||||
break;
|
||||
default:
|
||||
#if FIX_CACHE
|
||||
write_cmd = iomem_malloc((cmd_len + rx_len) * sizeof(uint32_t));
|
||||
#else
|
||||
write_cmd = malloc((cmd_len + rx_len) * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
write_cmd[i] = cmd_buff[i];
|
||||
read_buf = &write_cmd[i];
|
||||
|
@ -763,8 +801,11 @@ void spi_receive_data_standard_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
rx_buff[i] = read_buf[i];
|
||||
break;
|
||||
}
|
||||
|
||||
#if FIX_CACHE
|
||||
iomem_free(write_cmd);
|
||||
#else
|
||||
free(write_cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_receive_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff,
|
||||
|
@ -887,14 +928,22 @@ void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
v_recv_len = rx_len / 4;
|
||||
break;
|
||||
case SPI_TRANS_SHORT:
|
||||
#if FIX_CACHE
|
||||
write_cmd = iomem_malloc(cmd_len + rx_len / 2 * sizeof(uint32_t));
|
||||
#else
|
||||
write_cmd = malloc(cmd_len + rx_len / 2 * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
write_cmd[i] = cmd_buff[i];
|
||||
read_buf = &write_cmd[i];
|
||||
v_recv_len = rx_len / 2;
|
||||
break;
|
||||
default:
|
||||
#if FIX_CACHE
|
||||
write_cmd = iomem_malloc(cmd_len + rx_len * sizeof(uint32_t));
|
||||
#else
|
||||
write_cmd = malloc(cmd_len + rx_len * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
write_cmd[i] = cmd_buff[i];
|
||||
read_buf = &write_cmd[i];
|
||||
|
@ -921,7 +970,13 @@ void spi_receive_data_multiple_dma(dmac_channel_number_t dma_send_channel_num,
|
|||
}
|
||||
|
||||
if(frame_width != SPI_TRANS_INT)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
iomem_free(write_cmd);
|
||||
#else
|
||||
free(write_cmd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void spi_send_data_multiple(spi_device_num_t spi_num, spi_chip_select_t chip_select, const uint32_t *cmd_buff,
|
||||
|
@ -979,7 +1034,11 @@ void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_nu
|
|||
switch(frame_width)
|
||||
{
|
||||
case SPI_TRANS_INT:
|
||||
#if FIX_CACHE
|
||||
buf = iomem_malloc(cmd_len * sizeof(uint32_t) + tx_len);
|
||||
#else
|
||||
buf = malloc(cmd_len * sizeof(uint32_t) + tx_len);
|
||||
#endif
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
buf[i] = cmd_buff[i];
|
||||
for(i = 0; i < tx_len / 4; i++)
|
||||
|
@ -987,7 +1046,11 @@ void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_nu
|
|||
v_send_len = cmd_len + tx_len / 4;
|
||||
break;
|
||||
case SPI_TRANS_SHORT:
|
||||
#if FIX_CACHE
|
||||
buf = iomem_malloc(cmd_len * sizeof(uint32_t) + tx_len / 2 * sizeof(uint32_t));
|
||||
#else
|
||||
buf = malloc(cmd_len * sizeof(uint32_t) + tx_len / 2 * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
buf[i] = cmd_buff[i];
|
||||
for(i = 0; i < tx_len / 2; i++)
|
||||
|
@ -995,7 +1058,11 @@ void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_nu
|
|||
v_send_len = cmd_len + tx_len / 2;
|
||||
break;
|
||||
default:
|
||||
#if FIX_CACHE
|
||||
buf = iomem_malloc((cmd_len + tx_len) * sizeof(uint32_t));
|
||||
#else
|
||||
buf = malloc((cmd_len + tx_len) * sizeof(uint32_t));
|
||||
#endif
|
||||
for(i = 0; i < cmd_len; i++)
|
||||
buf[i] = cmd_buff[i];
|
||||
for(i = 0; i < tx_len; i++)
|
||||
|
@ -1006,7 +1073,11 @@ void spi_send_data_multiple_dma(dmac_channel_number_t channel_num, spi_device_nu
|
|||
|
||||
spi_send_data_normal_dma(channel_num, spi_num, chip_select, buf, v_send_len, SPI_TRANS_INT);
|
||||
|
||||
#if FIX_CACHE
|
||||
iomem_free((void *)buf);
|
||||
#else
|
||||
free((void *)buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_fill_data_dma(dmac_channel_number_t channel_num, spi_device_num_t spi_num, spi_chip_select_t chip_select,
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "sysctl.h"
|
||||
#include "uart.h"
|
||||
#include "utils.h"
|
||||
#include "iomem.h"
|
||||
|
||||
#define __UART_BRATE_CONST 16
|
||||
|
||||
|
@ -158,12 +159,18 @@ static int uart_dma_callback(void *ctx)
|
|||
size_t v_buf_len = v_uart_dma_instance->buf_len;
|
||||
uint8_t *v_buffer = v_uart_dma_instance->buffer;
|
||||
uint32_t *v_recv_buffer = v_uart_dma_instance->malloc_buffer;
|
||||
|
||||
for(size_t i = 0; i < v_buf_len; i++)
|
||||
{
|
||||
v_buffer[i] = v_recv_buffer[i];
|
||||
}
|
||||
}
|
||||
#if FIX_CACHE
|
||||
iomem_free(v_uart_dma_instance->malloc_buffer);
|
||||
#else
|
||||
free(v_uart_dma_instance->malloc_buffer);
|
||||
#endif
|
||||
v_uart_dma_instance->malloc_buffer = NULL;
|
||||
if(v_uart_dma_instance->uart_int_instance.callback)
|
||||
v_uart_dma_instance->uart_int_instance.callback(v_uart_dma_instance->uart_int_instance.ctx);
|
||||
return 0;
|
||||
|
@ -184,27 +191,42 @@ int uart_receive_data(uart_device_number_t channel, char *buffer, size_t buf_len
|
|||
|
||||
void uart_receive_data_dma(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel, uint8_t *buffer, size_t buf_len)
|
||||
{
|
||||
uint32_t *v_recv_buf = malloc(buf_len * sizeof(uint32_t));
|
||||
#if FIX_CACHE
|
||||
uint32_t *v_recv_buf = (uint32_t *)iomem_malloc(buf_len * sizeof(uint32_t));
|
||||
#else
|
||||
uint32_t *v_recv_buf = (uint32_t *)malloc(buf_len * sizeof(uint32_t));
|
||||
#endif
|
||||
configASSERT(v_recv_buf != NULL);
|
||||
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2);
|
||||
|
||||
dmac_set_single_mode(dmac_channel, (void *)(&uart[uart_channel]->RBR), v_recv_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len);
|
||||
|
||||
dmac_wait_done(dmac_channel);
|
||||
for(uint32_t i = 0; i < buf_len; i++)
|
||||
{
|
||||
buffer[i] = (uint8_t)(v_recv_buf[i] & 0xff);
|
||||
}
|
||||
#if FIX_CACHE
|
||||
iomem_free(v_recv_buf);
|
||||
#else
|
||||
free(v_recv_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void uart_receive_data_dma_irq(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel,
|
||||
uint8_t *buffer, size_t buf_len, plic_irq_callback_t uart_callback,
|
||||
void *ctx, uint32_t priority)
|
||||
{
|
||||
uint32_t *v_recv_buf = malloc(buf_len * sizeof(uint32_t));
|
||||
#if FIX_CACHE
|
||||
uint32_t *v_recv_buf = (uint32_t *)iomem_malloc(buf_len * sizeof(uint32_t));
|
||||
#else
|
||||
uint32_t *v_recv_buf = (uint32_t *)malloc(buf_len * sizeof(uint32_t));
|
||||
#endif
|
||||
configASSERT(v_recv_buf != NULL);
|
||||
|
||||
|
||||
uart_recv_dma_instance[uart_channel].dmac_channel = dmac_channel;
|
||||
uart_recv_dma_instance[uart_channel].uart_num = uart_channel;
|
||||
uart_recv_dma_instance[uart_channel].malloc_buffer = v_recv_buf;
|
||||
|
@ -217,7 +239,7 @@ void uart_receive_data_dma_irq(uart_device_number_t uart_channel, dmac_channel_n
|
|||
dmac_irq_register(dmac_channel, uart_dma_callback, &uart_recv_dma_instance[uart_channel], priority);
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_RX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(dmac_channel, (void *)(&uart[uart_channel]->RBR), v_recv_buf, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len);
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len);
|
||||
}
|
||||
|
||||
int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_len)
|
||||
|
@ -233,22 +255,37 @@ int uart_send_data(uart_device_number_t channel, const char *buffer, size_t buf_
|
|||
|
||||
void uart_send_data_dma(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel, const uint8_t *buffer, size_t buf_len)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
uint32_t *v_send_buf = iomem_malloc(buf_len * sizeof(uint32_t));
|
||||
#else
|
||||
uint32_t *v_send_buf = malloc(buf_len * sizeof(uint32_t));
|
||||
#endif
|
||||
configASSERT(v_send_buf != NULL);
|
||||
|
||||
for(uint32_t i = 0; i < buf_len; i++)
|
||||
v_send_buf[i] = buffer[i];
|
||||
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dmac_channel, SYSCTL_DMA_SELECT_UART1_TX_REQ + uart_channel * 2);
|
||||
dmac_set_single_mode(dmac_channel, v_send_buf, (void *)(&uart[uart_channel]->THR), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len);
|
||||
DMAC_MSIZE_1, DMAC_TRANS_WIDTH_32, buf_len);
|
||||
|
||||
dmac_wait_done(dmac_channel);
|
||||
#if FIX_CACHE
|
||||
iomem_free((void *)v_send_buf);
|
||||
#else
|
||||
free((void *)v_send_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void uart_send_data_dma_irq(uart_device_number_t uart_channel, dmac_channel_number_t dmac_channel,
|
||||
const uint8_t *buffer, size_t buf_len, plic_irq_callback_t uart_callback,
|
||||
void *ctx, uint32_t priority)
|
||||
{
|
||||
#if FIX_CACHE
|
||||
uint32_t *v_send_buf = iomem_malloc(buf_len * sizeof(uint32_t));
|
||||
#else
|
||||
uint32_t *v_send_buf = malloc(buf_len * sizeof(uint32_t));
|
||||
#endif
|
||||
configASSERT(v_send_buf != NULL);
|
||||
|
||||
uart_send_dma_instance[uart_channel] = (uart_dma_instance_t){
|
||||
|
|
|
@ -41,3 +41,11 @@ uint32_t get_gpio_bit(volatile uint32_t *bits, size_t offset)
|
|||
{
|
||||
return get_bit(bits, 1, offset);
|
||||
}
|
||||
|
||||
uint32_t is_memory_cache(uintptr_t address)
|
||||
{
|
||||
#define MEM_CACHE_LEN (6 * 1024 * 1024)
|
||||
|
||||
return ((address >= 0x80000000) && (address < 0x80000000 + MEM_CACHE_LEN));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FREERTOS_CONFIG_H
|
||||
#define FREERTOS_CONFIG_H
|
||||
/*-----------------------------------------------------------
|
||||
* Application specific definitions.
|
||||
*
|
||||
* These definitions should be adjusted for your particular hardware and
|
||||
* application requirements.
|
||||
*
|
||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
||||
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
|
||||
*
|
||||
* See http://www.freertos.org/a00110.html.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* clock */
|
||||
#define configCPU_CLOCK_HZ uxPortGetCPUClock()
|
||||
#define configTICK_CLOCK_HZ ( configCPU_CLOCK_HZ / 50 )
|
||||
#define configTICK_RATE_HZ ( ( TickType_t ) 100 )
|
||||
|
||||
/* multithreading */
|
||||
#define configUSE_NEWLIB_REENTRANT 1
|
||||
|
||||
#define configUSE_PREEMPTION 1
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
|
||||
#define configMAX_PRIORITIES ( 5 )
|
||||
#define configMAX_TASK_NAME_LEN ( 16 )
|
||||
#define configUSE_TRACE_FACILITY 0
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 0
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
|
||||
/* TLS */
|
||||
enum
|
||||
{
|
||||
PTHREAD_TLS_INDEX = 0
|
||||
};
|
||||
|
||||
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1
|
||||
|
||||
/* mutex */
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
|
||||
/* hooks */
|
||||
#define configUSE_MALLOC_FAILED_HOOK 0
|
||||
#define configUSE_IDLE_HOOK 1
|
||||
#define configUSE_TICK_HOOK 0
|
||||
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
|
||||
|
||||
/* memory */
|
||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 2048 )
|
||||
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 1024 * 512 ) )
|
||||
#define configSUPPORT_STATIC_ALLOCATION 1
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
|
||||
#define configUSE_APPLICATION_TASK_TAG 1
|
||||
#define configUSE_COUNTING_SEMAPHORES 1
|
||||
#define configUSE_TICKLESS_IDLE 1
|
||||
#define configGENERATE_RUN_TIME_STATS 0
|
||||
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
|
||||
|
||||
/* Co-routine definitions. */
|
||||
#define configUSE_CO_ROUTINES 0
|
||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||
|
||||
/* Software timer definitions. */
|
||||
#define configUSE_TIMERS 0
|
||||
#define configTIMER_TASK_PRIORITY ( 2 )
|
||||
#define configTIMER_QUEUE_LENGTH 2
|
||||
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE )
|
||||
|
||||
/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */
|
||||
#define INCLUDE_vTaskPrioritySet 1
|
||||
#define INCLUDE_uxTaskPriorityGet 1
|
||||
#define INCLUDE_vTaskDelete 1
|
||||
#define INCLUDE_vTaskCleanUpResources 1
|
||||
#define INCLUDE_vTaskSuspend 1
|
||||
#define INCLUDE_vTaskDelayUntil 1
|
||||
#define INCLUDE_vTaskDelay 1
|
||||
#define INCLUDE_eTaskGetState 1
|
||||
#define INCLUDE_xTaskAbortDelay 1
|
||||
|
||||
#define INCLUDE_xSemaphoreGetMutexHolder 1
|
||||
|
||||
/* Diagnostics */
|
||||
#define configCHECK_FOR_STACK_OVERFLOW 1
|
||||
|
||||
#ifdef configASSERT
|
||||
#undef configASSERT
|
||||
#endif
|
||||
/* configASSERT behaviour */
|
||||
extern void vPortFatal(const char* file, int line, const char* message);
|
||||
/* Normal assert() semantics without relying on the provision of an assert.h header file. */
|
||||
#define configASSERT( x ) if( ( x ) == 0 ) { \
|
||||
vPortFatal(__FILE__, __LINE__, #x); \
|
||||
}
|
||||
|
||||
#endif /* FREERTOS_CONFIG_H */
|
|
@ -0,0 +1,100 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <atomic.h>
|
||||
#include <clint.h>
|
||||
#include <core_sync.h>
|
||||
#include <encoding.h>
|
||||
#include <plic.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
volatile UBaseType_t g_core_pending_switch[portNUM_PROCESSORS] = { 0 };
|
||||
static volatile UBaseType_t s_core_sync_events[portNUM_PROCESSORS] = { 0 };
|
||||
static volatile TaskHandle_t s_pending_to_add_tasks[portNUM_PROCESSORS] = { 0 };
|
||||
static volatile UBaseType_t s_core_sync_in_progress[portNUM_PROCESSORS] = { 0 };
|
||||
|
||||
uintptr_t handle_irq_m_soft(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
|
||||
{
|
||||
uint64_t core_id = uxPortGetProcessorId();
|
||||
atomic_set(&s_core_sync_in_progress[core_id], 1);
|
||||
switch (s_core_sync_events[core_id])
|
||||
{
|
||||
case CORE_SYNC_ADD_TCB:
|
||||
{
|
||||
TaskHandle_t newTask = atomic_read(&s_pending_to_add_tasks[core_id]);
|
||||
if (newTask)
|
||||
{
|
||||
vAddNewTaskToCurrentReadyList(newTask);
|
||||
atomic_set(&s_pending_to_add_tasks[core_id], NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
core_sync_complete(core_id);
|
||||
return epc;
|
||||
}
|
||||
|
||||
uintptr_t handle_irq_m_timer(uintptr_t cause, uintptr_t epc, uintptr_t regs[32], uintptr_t fregs[32])
|
||||
{
|
||||
prvSetNextTimerInterrupt();
|
||||
|
||||
/* Increment the RTOS tick. */
|
||||
if (xTaskIncrementTick() != pdFALSE)
|
||||
{
|
||||
core_sync_request_context_switch(uxPortGetProcessorId());
|
||||
}
|
||||
|
||||
return epc;
|
||||
}
|
||||
|
||||
void core_sync_request_context_switch(uint64_t core_id)
|
||||
{
|
||||
atomic_set(&g_core_pending_switch[core_id], 1);
|
||||
clint_ipi_send(core_id);
|
||||
}
|
||||
|
||||
void core_sync_complete(uint64_t core_id)
|
||||
{
|
||||
if (atomic_read(&g_core_pending_switch[core_id]) == 0)
|
||||
clint_ipi_clear(core_id);
|
||||
atomic_set(&s_core_sync_events[core_id], CORE_SYNC_NONE);
|
||||
atomic_set(&s_core_sync_in_progress[core_id], 0);
|
||||
}
|
||||
|
||||
void core_sync_complete_context_switch(uint64_t core_id)
|
||||
{
|
||||
if (atomic_read(&s_core_sync_events[core_id]) == CORE_SYNC_NONE)
|
||||
clint_ipi_clear(core_id);
|
||||
atomic_set(&g_core_pending_switch[core_id], 0);
|
||||
}
|
||||
|
||||
int core_sync_is_in_progress(uint64_t core_id)
|
||||
{
|
||||
return !!atomic_read(&s_core_sync_in_progress[core_id]);
|
||||
}
|
||||
|
||||
void vPortAddNewTaskToReadyListAsync(UBaseType_t uxPsrId, void* pxNewTaskHandle)
|
||||
{
|
||||
// Wait for last adding tcb complete
|
||||
while (atomic_read(&s_pending_to_add_tasks[uxPsrId]));
|
||||
atomic_set(&s_pending_to_add_tasks[uxPsrId], pxNewTaskHandle);
|
||||
|
||||
while (atomic_cas(&s_core_sync_events[uxPsrId], CORE_SYNC_NONE, CORE_SYNC_ADD_TCB) != CORE_SYNC_NONE)
|
||||
;
|
||||
clint_ipi_send(uxPsrId);
|
||||
}
|
|
@ -0,0 +1,367 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "croutine.h"
|
||||
|
||||
/* Remove the whole file is co-routines are not being used. */
|
||||
#if( configUSE_CO_ROUTINES != 0 )
|
||||
|
||||
/*
|
||||
* Some kernel aware debuggers require data to be viewed to be global, rather
|
||||
* than file scope.
|
||||
*/
|
||||
#ifdef portREMOVE_STATIC_QUALIFIER
|
||||
#define static
|
||||
#endif
|
||||
|
||||
|
||||
/* Lists for ready and blocked co-routines. --------------------*/
|
||||
static List_t pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
|
||||
static List_t xDelayedCoRoutineList1; /*< Delayed co-routines. */
|
||||
static List_t xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
|
||||
static List_t * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
|
||||
static List_t * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
|
||||
static List_t xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
|
||||
|
||||
/* Other file private variables. --------------------------------*/
|
||||
CRCB_t * pxCurrentCoRoutine = NULL;
|
||||
static UBaseType_t uxTopCoRoutineReadyPriority = 0;
|
||||
static TickType_t xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
|
||||
|
||||
/* The initial state of the co-routine when it is created. */
|
||||
#define corINITIAL_STATE ( 0 )
|
||||
|
||||
/*
|
||||
* Place the co-routine represented by pxCRCB into the appropriate ready queue
|
||||
* for the priority. It is inserted at the end of the list.
|
||||
*
|
||||
* This macro accesses the co-routine ready lists and therefore must not be
|
||||
* used from within an ISR.
|
||||
*/
|
||||
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
|
||||
{ \
|
||||
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
|
||||
{ \
|
||||
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
|
||||
} \
|
||||
vListInsertEnd( ( List_t * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility to ready all the lists used by the scheduler. This is called
|
||||
* automatically upon the creation of the first co-routine.
|
||||
*/
|
||||
static void prvInitialiseCoRoutineLists( void );
|
||||
|
||||
/*
|
||||
* Co-routines that are readied by an interrupt cannot be placed directly into
|
||||
* the ready lists (there is no mutual exclusion). Instead they are placed in
|
||||
* in the pending ready list in order that they can later be moved to the ready
|
||||
* list by the co-routine scheduler.
|
||||
*/
|
||||
static void prvCheckPendingReadyList( void );
|
||||
|
||||
/*
|
||||
* Macro that looks at the list of co-routines that are currently delayed to
|
||||
* see if any require waking.
|
||||
*
|
||||
* Co-routines are stored in the queue in the order of their wake time -
|
||||
* meaning once one co-routine has been found whose timer has not expired
|
||||
* we need not look any further down the list.
|
||||
*/
|
||||
static void prvCheckDelayedList( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
CRCB_t *pxCoRoutine;
|
||||
|
||||
/* Allocate the memory that will store the co-routine control block. */
|
||||
pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
|
||||
if( pxCoRoutine )
|
||||
{
|
||||
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
|
||||
be created and the co-routine data structures need initialising. */
|
||||
if( pxCurrentCoRoutine == NULL )
|
||||
{
|
||||
pxCurrentCoRoutine = pxCoRoutine;
|
||||
prvInitialiseCoRoutineLists();
|
||||
}
|
||||
|
||||
/* Check the priority is within limits. */
|
||||
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
|
||||
{
|
||||
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
|
||||
}
|
||||
|
||||
/* Fill out the co-routine control block from the function parameters. */
|
||||
pxCoRoutine->uxState = corINITIAL_STATE;
|
||||
pxCoRoutine->uxPriority = uxPriority;
|
||||
pxCoRoutine->uxIndex = uxIndex;
|
||||
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
|
||||
|
||||
/* Initialise all the other co-routine control block parameters. */
|
||||
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
|
||||
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
|
||||
|
||||
/* Set the co-routine control block as a link back from the ListItem_t.
|
||||
This is so we can get back to the containing CRCB from a generic item
|
||||
in a list. */
|
||||
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
|
||||
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
|
||||
|
||||
/* Event lists are always in priority order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), ( ( TickType_t ) configMAX_CO_ROUTINE_PRIORITIES - ( TickType_t ) uxPriority ) );
|
||||
|
||||
/* Now the co-routine has been initialised it can be added to the ready
|
||||
list at the correct priority. */
|
||||
prvAddCoRoutineToReadyQueue( pxCoRoutine );
|
||||
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList )
|
||||
{
|
||||
TickType_t xTimeToWake;
|
||||
|
||||
/* Calculate the time to wake - this may overflow but this is
|
||||
not a problem. */
|
||||
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
|
||||
|
||||
/* We must remove ourselves from the ready list before adding
|
||||
ourselves to the blocked list as the same list item is used for
|
||||
both lists. */
|
||||
( void ) uxListRemove( ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||
|
||||
/* The list item will be inserted in wake time order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xCoRoutineTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the
|
||||
overflow list. */
|
||||
vListInsert( ( List_t * ) pxOverflowDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the
|
||||
current block list. */
|
||||
vListInsert( ( List_t * ) pxDelayedCoRoutineList, ( ListItem_t * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||
}
|
||||
|
||||
if( pxEventList )
|
||||
{
|
||||
/* Also add the co-routine to an event list. If this is done then the
|
||||
function must be called with interrupts disabled. */
|
||||
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckPendingReadyList( void )
|
||||
{
|
||||
/* Are there any co-routines waiting to get moved to the ready list? These
|
||||
are co-routines that have been readied by an ISR. The ISR cannot access
|
||||
the ready lists itself. */
|
||||
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
|
||||
{
|
||||
CRCB_t *pxUnblockedCRCB;
|
||||
|
||||
/* The pending ready list can be accessed by an ISR. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
{
|
||||
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
|
||||
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
|
||||
( void ) uxListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
|
||||
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckDelayedList( void )
|
||||
{
|
||||
CRCB_t *pxCRCB;
|
||||
|
||||
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
|
||||
while( xPassedTicks )
|
||||
{
|
||||
xCoRoutineTickCount++;
|
||||
xPassedTicks--;
|
||||
|
||||
/* If the tick count has overflowed we need to swap the ready lists. */
|
||||
if( xCoRoutineTickCount == 0 )
|
||||
{
|
||||
List_t * pxTemp;
|
||||
|
||||
/* Tick count has overflowed so we need to swap the delay lists. If there are
|
||||
any items in pxDelayedCoRoutineList here then there is an error! */
|
||||
pxTemp = pxDelayedCoRoutineList;
|
||||
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
|
||||
pxOverflowDelayedCoRoutineList = pxTemp;
|
||||
}
|
||||
|
||||
/* See if this tick has made a timeout expire. */
|
||||
while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
|
||||
{
|
||||
pxCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
|
||||
|
||||
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
|
||||
{
|
||||
/* Timeout not yet expired. */
|
||||
break;
|
||||
}
|
||||
|
||||
portDISABLE_INTERRUPTS();
|
||||
{
|
||||
/* The event could have occurred just before this critical
|
||||
section. If this is the case then the generic list item will
|
||||
have been moved to the pending ready list and the following
|
||||
line is still valid. Also the pvContainer parameter will have
|
||||
been set to NULL so the following lines are also valid. */
|
||||
( void ) uxListRemove( &( pxCRCB->xGenericListItem ) );
|
||||
|
||||
/* Is the co-routine waiting on an event also? */
|
||||
if( pxCRCB->xEventListItem.pvContainer )
|
||||
{
|
||||
( void ) uxListRemove( &( pxCRCB->xEventListItem ) );
|
||||
}
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
|
||||
prvAddCoRoutineToReadyQueue( pxCRCB );
|
||||
}
|
||||
}
|
||||
|
||||
xLastTickCount = xCoRoutineTickCount;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCoRoutineSchedule( void )
|
||||
{
|
||||
/* See if any co-routines readied by events need moving to the ready lists. */
|
||||
prvCheckPendingReadyList();
|
||||
|
||||
/* See if any delayed co-routines have timed out. */
|
||||
prvCheckDelayedList();
|
||||
|
||||
/* Find the highest priority queue that contains ready co-routines. */
|
||||
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
|
||||
{
|
||||
if( uxTopCoRoutineReadyPriority == 0 )
|
||||
{
|
||||
/* No more co-routines to check. */
|
||||
return;
|
||||
}
|
||||
--uxTopCoRoutineReadyPriority;
|
||||
}
|
||||
|
||||
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
|
||||
of the same priority get an equal share of the processor time. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
|
||||
|
||||
/* Call the co-routine. */
|
||||
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
|
||||
|
||||
return;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInitialiseCoRoutineLists( void )
|
||||
{
|
||||
UBaseType_t uxPriority;
|
||||
|
||||
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
|
||||
{
|
||||
vListInitialise( ( List_t * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
|
||||
}
|
||||
|
||||
vListInitialise( ( List_t * ) &xDelayedCoRoutineList1 );
|
||||
vListInitialise( ( List_t * ) &xDelayedCoRoutineList2 );
|
||||
vListInitialise( ( List_t * ) &xPendingReadyCoRoutineList );
|
||||
|
||||
/* Start with pxDelayedCoRoutineList using list1 and the
|
||||
pxOverflowDelayedCoRoutineList using list2. */
|
||||
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
|
||||
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList )
|
||||
{
|
||||
CRCB_t *pxUnblockedCRCB;
|
||||
BaseType_t xReturn;
|
||||
|
||||
/* This function is called from within an interrupt. It can only access
|
||||
event lists and the pending ready list. This function assumes that a
|
||||
check has already been made to ensure pxEventList is not empty. */
|
||||
pxUnblockedCRCB = ( CRCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
|
||||
( void ) uxListRemove( &( pxUnblockedCRCB->xEventListItem ) );
|
||||
vListInsertEnd( ( List_t * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
|
||||
|
||||
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif /* configUSE_CO_ROUTINES == 0 */
|
||||
|
|
@ -0,0 +1,752 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "timers.h"
|
||||
#include "event_groups.h"
|
||||
|
||||
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
|
||||
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
|
||||
header files above, but not in this file, in order to generate the correct
|
||||
privileged Vs unprivileged linkage and placement. */
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
|
||||
|
||||
/* The following bit fields convey control information in a task's event list
|
||||
item value. It is important they don't clash with the
|
||||
taskEVENT_LIST_ITEM_VALUE_IN_USE definition. */
|
||||
#if configUSE_16_BIT_TICKS == 1
|
||||
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x0100U
|
||||
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x0200U
|
||||
#define eventWAIT_FOR_ALL_BITS 0x0400U
|
||||
#define eventEVENT_BITS_CONTROL_BYTES 0xff00U
|
||||
#else
|
||||
#define eventCLEAR_EVENTS_ON_EXIT_BIT 0x01000000UL
|
||||
#define eventUNBLOCKED_DUE_TO_BIT_SET 0x02000000UL
|
||||
#define eventWAIT_FOR_ALL_BITS 0x04000000UL
|
||||
#define eventEVENT_BITS_CONTROL_BYTES 0xff000000UL
|
||||
#endif
|
||||
|
||||
typedef struct xEventGroupDefinition
|
||||
{
|
||||
EventBits_t uxEventBits;
|
||||
List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */
|
||||
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
UBaseType_t uxEventGroupNumber;
|
||||
#endif
|
||||
|
||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
|
||||
#endif
|
||||
} EventGroup_t;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Test the bits set in uxCurrentEventBits to see if the wait condition is met.
|
||||
* The wait condition is defined by xWaitForAllBits. If xWaitForAllBits is
|
||||
* pdTRUE then the wait condition is met if all the bits set in uxBitsToWaitFor
|
||||
* are also set in uxCurrentEventBits. If xWaitForAllBits is pdFALSE then the
|
||||
* wait condition is met if any of the bits set in uxBitsToWait for are also set
|
||||
* in uxCurrentEventBits.
|
||||
*/
|
||||
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
|
||||
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
|
||||
{
|
||||
EventGroup_t *pxEventBits;
|
||||
|
||||
/* A StaticEventGroup_t object must be provided. */
|
||||
configASSERT( pxEventGroupBuffer );
|
||||
|
||||
#if( configASSERT_DEFINED == 1 )
|
||||
{
|
||||
/* Sanity check that the size of the structure used to declare a
|
||||
variable of type StaticEventGroup_t equals the size of the real
|
||||
event group structure. */
|
||||
volatile size_t xSize = sizeof( StaticEventGroup_t );
|
||||
configASSERT( xSize == sizeof( EventGroup_t ) );
|
||||
}
|
||||
#endif /* configASSERT_DEFINED */
|
||||
|
||||
/* The user has provided a statically allocated event group - use it. */
|
||||
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
|
||||
|
||||
if( pxEventBits != NULL )
|
||||
{
|
||||
pxEventBits->uxEventBits = 0;
|
||||
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Both static and dynamic allocation can be used, so note that
|
||||
this event group was created statically in case the event group
|
||||
is later deleted. */
|
||||
pxEventBits->ucStaticallyAllocated = pdTRUE;
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
|
||||
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEVENT_GROUP_CREATE_FAILED();
|
||||
}
|
||||
|
||||
return ( EventGroupHandle_t ) pxEventBits;
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
|
||||
EventGroupHandle_t xEventGroupCreate( void )
|
||||
{
|
||||
EventGroup_t *pxEventBits;
|
||||
|
||||
/* Allocate the event group. */
|
||||
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );
|
||||
|
||||
if( pxEventBits != NULL )
|
||||
{
|
||||
pxEventBits->uxEventBits = 0;
|
||||
vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );
|
||||
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
{
|
||||
/* Both static and dynamic allocation can be used, so note this
|
||||
event group was allocated statically in case the event group is
|
||||
later deleted. */
|
||||
pxEventBits->ucStaticallyAllocated = pdFALSE;
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
traceEVENT_GROUP_CREATE( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceEVENT_GROUP_CREATE_FAILED();
|
||||
}
|
||||
|
||||
return ( EventGroupHandle_t ) pxEventBits;
|
||||
}
|
||||
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait )
|
||||
{
|
||||
EventBits_t uxOriginalBitValue, uxReturn;
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
BaseType_t xAlreadyYielded;
|
||||
BaseType_t xTimeoutOccurred = pdFALSE;
|
||||
|
||||
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||
configASSERT( uxBitsToWaitFor != 0 );
|
||||
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||
{
|
||||
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
uxOriginalBitValue = pxEventBits->uxEventBits;
|
||||
|
||||
( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet );
|
||||
|
||||
if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor )
|
||||
{
|
||||
/* All the rendezvous bits are now set - no need to block. */
|
||||
uxReturn = ( uxOriginalBitValue | uxBitsToSet );
|
||||
|
||||
/* Rendezvous always clear the bits. They will have been cleared
|
||||
already unless this is the only task in the rendezvous. */
|
||||
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||
|
||||
xTicksToWait = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xTicksToWait != ( TickType_t ) 0 )
|
||||
{
|
||||
traceEVENT_GROUP_SYNC_BLOCK( xEventGroup, uxBitsToSet, uxBitsToWaitFor );
|
||||
|
||||
/* Store the bits that the calling task is waiting for in the
|
||||
task's event list item so the kernel knows when a match is
|
||||
found. Then enter the blocked state. */
|
||||
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait );
|
||||
|
||||
/* This assignment is obsolete as uxReturn will get set after
|
||||
the task unblocks, but some compilers mistakenly generate a
|
||||
warning about uxReturn being returned without being set if the
|
||||
assignment is omitted. */
|
||||
uxReturn = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The rendezvous bits were not set, but no block time was
|
||||
specified - just return the current event bit value. */
|
||||
uxReturn = pxEventBits->uxEventBits;
|
||||
xTimeoutOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
xAlreadyYielded = xTaskResumeAll();
|
||||
|
||||
if( xTicksToWait != ( TickType_t ) 0 )
|
||||
{
|
||||
if( xAlreadyYielded == pdFALSE )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* The task blocked to wait for its required bits to be set - at this
|
||||
point either the required bits were set or the block time expired. If
|
||||
the required bits were set they will have been stored in the task's
|
||||
event list item, and they should now be retrieved then cleared. */
|
||||
uxReturn = uxTaskResetEventItemValue();
|
||||
|
||||
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
|
||||
{
|
||||
/* The task timed out, just return the current event bit value. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
uxReturn = pxEventBits->uxEventBits;
|
||||
|
||||
/* Although the task got here because it timed out before the
|
||||
bits it was waiting for were set, it is possible that since it
|
||||
unblocked another task has set the bits. If this is the case
|
||||
then it needs to clear the bits before exiting. */
|
||||
if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor )
|
||||
{
|
||||
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
xTimeoutOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The task unblocked because the bits were set. */
|
||||
}
|
||||
|
||||
/* Control bits might be set as the task had blocked should not be
|
||||
returned. */
|
||||
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
|
||||
}
|
||||
|
||||
traceEVENT_GROUP_SYNC_END( xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred );
|
||||
|
||||
/* Prevent compiler warnings when trace macros are not used. */
|
||||
( void ) xTimeoutOccurred;
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
|
||||
{
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
EventBits_t uxReturn, uxControlBits = 0;
|
||||
BaseType_t xWaitConditionMet, xAlreadyYielded;
|
||||
BaseType_t xTimeoutOccurred = pdFALSE;
|
||||
|
||||
/* Check the user is not attempting to wait on the bits used by the kernel
|
||||
itself, and that at least one bit is being requested. */
|
||||
configASSERT( xEventGroup );
|
||||
configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||
configASSERT( uxBitsToWaitFor != 0 );
|
||||
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||
{
|
||||
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
|
||||
|
||||
/* Check to see if the wait condition is already met or not. */
|
||||
xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );
|
||||
|
||||
if( xWaitConditionMet != pdFALSE )
|
||||
{
|
||||
/* The wait condition has already been met so there is no need to
|
||||
block. */
|
||||
uxReturn = uxCurrentEventBits;
|
||||
xTicksToWait = ( TickType_t ) 0;
|
||||
|
||||
/* Clear the wait bits if requested to do so. */
|
||||
if( xClearOnExit != pdFALSE )
|
||||
{
|
||||
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else if( xTicksToWait == ( TickType_t ) 0 )
|
||||
{
|
||||
/* The wait condition has not been met, but no block time was
|
||||
specified, so just return the current value. */
|
||||
uxReturn = uxCurrentEventBits;
|
||||
xTimeoutOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The task is going to block to wait for its required bits to be
|
||||
set. uxControlBits are used to remember the specified behaviour of
|
||||
this call to xEventGroupWaitBits() - for use when the event bits
|
||||
unblock the task. */
|
||||
if( xClearOnExit != pdFALSE )
|
||||
{
|
||||
uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
if( xWaitForAllBits != pdFALSE )
|
||||
{
|
||||
uxControlBits |= eventWAIT_FOR_ALL_BITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Store the bits that the calling task is waiting for in the
|
||||
task's event list item so the kernel knows when a match is
|
||||
found. Then enter the blocked state. */
|
||||
vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );
|
||||
|
||||
/* This is obsolete as it will get set after the task unblocks, but
|
||||
some compilers mistakenly generate a warning about the variable
|
||||
being returned without being set if it is not done. */
|
||||
uxReturn = 0;
|
||||
|
||||
traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
|
||||
}
|
||||
}
|
||||
xAlreadyYielded = xTaskResumeAll();
|
||||
|
||||
if( xTicksToWait != ( TickType_t ) 0 )
|
||||
{
|
||||
if( xAlreadyYielded == pdFALSE )
|
||||
{
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* The task blocked to wait for its required bits to be set - at this
|
||||
point either the required bits were set or the block time expired. If
|
||||
the required bits were set they will have been stored in the task's
|
||||
event list item, and they should now be retrieved then cleared. */
|
||||
uxReturn = uxTaskResetEventItemValue();
|
||||
|
||||
if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
|
||||
{
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
/* The task timed out, just return the current event bit value. */
|
||||
uxReturn = pxEventBits->uxEventBits;
|
||||
|
||||
/* It is possible that the event bits were updated between this
|
||||
task leaving the Blocked state and running again. */
|
||||
if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
|
||||
{
|
||||
if( xClearOnExit != pdFALSE )
|
||||
{
|
||||
pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
xTimeoutOccurred = pdTRUE;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The task unblocked because the bits were set. */
|
||||
}
|
||||
|
||||
/* The task blocked so control bits may have been set. */
|
||||
uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
|
||||
}
|
||||
traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );
|
||||
|
||||
/* Prevent compiler warnings when trace macros are not used. */
|
||||
( void ) xTimeoutOccurred;
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
{
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
EventBits_t uxReturn;
|
||||
|
||||
/* Check the user is not attempting to clear the bits used by the kernel
|
||||
itself. */
|
||||
configASSERT( xEventGroup );
|
||||
configASSERT( ( uxBitsToClear & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
traceEVENT_GROUP_CLEAR_BITS( xEventGroup, uxBitsToClear );
|
||||
|
||||
/* The value returned is the event group value prior to the bits being
|
||||
cleared. */
|
||||
uxReturn = pxEventBits->uxEventBits;
|
||||
|
||||
/* Clear the bits. */
|
||||
pxEventBits->uxEventBits &= ~uxBitsToClear;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
|
||||
|
||||
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
traceEVENT_GROUP_CLEAR_BITS_FROM_ISR( xEventGroup, uxBitsToClear );
|
||||
xReturn = xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL );
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
UBaseType_t uxSavedInterruptStatus;
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
EventBits_t uxReturn;
|
||||
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
|
||||
{
|
||||
uxReturn = pxEventBits->uxEventBits;
|
||||
}
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
|
||||
{
|
||||
ListItem_t *pxListItem, *pxNext;
|
||||
ListItem_t const *pxListEnd;
|
||||
List_t *pxList;
|
||||
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
BaseType_t xMatchFound = pdFALSE;
|
||||
|
||||
/* Check the user is not attempting to set the bits used by the kernel
|
||||
itself. */
|
||||
configASSERT( xEventGroup );
|
||||
configASSERT( ( uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
|
||||
|
||||
pxList = &( pxEventBits->xTasksWaitingForBits );
|
||||
pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
traceEVENT_GROUP_SET_BITS( xEventGroup, uxBitsToSet );
|
||||
|
||||
pxListItem = listGET_HEAD_ENTRY( pxList );
|
||||
|
||||
/* Set the bits. */
|
||||
pxEventBits->uxEventBits |= uxBitsToSet;
|
||||
|
||||
/* See if the new bit value should unblock any tasks. */
|
||||
while( pxListItem != pxListEnd )
|
||||
{
|
||||
pxNext = listGET_NEXT( pxListItem );
|
||||
uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
|
||||
xMatchFound = pdFALSE;
|
||||
|
||||
/* Split the bits waited for from the control bits. */
|
||||
uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
|
||||
uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
|
||||
|
||||
if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
|
||||
{
|
||||
/* Just looking for single bit being set. */
|
||||
if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
|
||||
{
|
||||
xMatchFound = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
|
||||
{
|
||||
/* All bits are set. */
|
||||
xMatchFound = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need all bits to be set, but not all the bits were set. */
|
||||
}
|
||||
|
||||
if( xMatchFound != pdFALSE )
|
||||
{
|
||||
/* The bits match. Should the bits be cleared on exit? */
|
||||
if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
|
||||
{
|
||||
uxBitsToClear |= uxBitsWaitedFor;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Store the actual event flag value in the task's event list
|
||||
item before removing the task from the event list. The
|
||||
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
|
||||
that is was unblocked due to its required bits matching, rather
|
||||
than because it timed out. */
|
||||
vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||
}
|
||||
|
||||
/* Move onto the next list item. Note pxListItem->pxNext is not
|
||||
used here as the list item may have been removed from the event list
|
||||
and inserted into the ready/pending reading list. */
|
||||
pxListItem = pxNext;
|
||||
}
|
||||
|
||||
/* Clear any bits that matched when the eventCLEAR_EVENTS_ON_EXIT_BIT
|
||||
bit was set in the control word. */
|
||||
pxEventBits->uxEventBits &= ~uxBitsToClear;
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
return pxEventBits->uxEventBits;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
traceEVENT_GROUP_DELETE( xEventGroup );
|
||||
|
||||
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
||||
{
|
||||
/* Unblock the task, returning 0 as the event list is being deleted
|
||||
and cannot therefore have any bits set. */
|
||||
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
||||
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||
}
|
||||
|
||||
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||
{
|
||||
/* The event group can only have been allocated dynamically - free
|
||||
it again. */
|
||||
vPortFree( pxEventBits );
|
||||
}
|
||||
#elif( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||
{
|
||||
/* The event group could have been allocated statically or
|
||||
dynamically, so check before attempting to free the memory. */
|
||||
if( pxEventBits->ucStaticallyAllocated == ( uint8_t ) pdFALSE )
|
||||
{
|
||||
vPortFree( pxEventBits );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* For internal use only - execute a 'set bits' command that was pended from
|
||||
an interrupt. */
|
||||
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet )
|
||||
{
|
||||
( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* For internal use only - execute a 'clear bits' command that was pended from
|
||||
an interrupt. */
|
||||
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear )
|
||||
{
|
||||
( void ) xEventGroupClearBits( pvEventGroup, ( EventBits_t ) ulBitsToClear );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits )
|
||||
{
|
||||
BaseType_t xWaitConditionMet = pdFALSE;
|
||||
|
||||
if( xWaitForAllBits == pdFALSE )
|
||||
{
|
||||
/* Task only has to wait for one bit within uxBitsToWaitFor to be
|
||||
set. Is one already set? */
|
||||
if( ( uxCurrentEventBits & uxBitsToWaitFor ) != ( EventBits_t ) 0 )
|
||||
{
|
||||
xWaitConditionMet = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Task has to wait for all the bits in uxBitsToWaitFor to be set.
|
||||
Are they set already? */
|
||||
if( ( uxCurrentEventBits & uxBitsToWaitFor ) == uxBitsToWaitFor )
|
||||
{
|
||||
xWaitConditionMet = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
|
||||
return xWaitConditionMet;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )
|
||||
|
||||
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken )
|
||||
{
|
||||
BaseType_t xReturn;
|
||||
|
||||
traceEVENT_GROUP_SET_BITS_FROM_ISR( xEventGroup, uxBitsToSet );
|
||||
xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken );
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if (configUSE_TRACE_FACILITY == 1)
|
||||
|
||||
UBaseType_t uxEventGroupGetNumber( void* xEventGroup )
|
||||
{
|
||||
UBaseType_t xReturn;
|
||||
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
|
||||
|
||||
if( xEventGroup == NULL )
|
||||
{
|
||||
xReturn = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pxEventBits->uxEventGroupNumber;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif /* configUSE_TRACE_FACILITY */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configUSE_TRACE_FACILITY == 1 )
|
||||
|
||||
void vEventGroupSetNumber( void * xEventGroup, UBaseType_t uxEventGroupNumber )
|
||||
{
|
||||
( ( EventGroup_t * ) xEventGroup )->uxEventGroupNumber = uxEventGroupNumber;
|
||||
}
|
||||
|
||||
#endif /* configUSE_TRACE_FACILITY */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,147 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef STACK_MACROS_H
|
||||
#define STACK_MACROS_H
|
||||
|
||||
#ifndef _MSC_VER /* Visual Studio doesn't support #warning. */
|
||||
#warning The name of this file has changed to stack_macros.h. Please update your code accordingly. This source file (which has the original name) will be removed in future released.
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Call the stack overflow hook function if the stack of the task being swapped
|
||||
* out is currently overflowed, or looks like it might have overflowed in the
|
||||
* past.
|
||||
*
|
||||
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
|
||||
* the current stack state only - comparing the current top of stack value to
|
||||
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
|
||||
* will also cause the last few stack bytes to be checked to ensure the value
|
||||
* to which the bytes were set when the task was created have not been
|
||||
* overwritten. Note this second test does not guarantee that an overflowed
|
||||
* stack will always be recognised.
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
\
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
|
||||
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||
\
|
||||
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
|
||||
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
|
||||
\
|
||||
\
|
||||
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
|
||||
\
|
||||
/* Has the extremity of the task stack ever been written over? */ \
|
||||
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Remove stack overflow macro if not being used. */
|
||||
#ifndef taskCHECK_FOR_STACK_OVERFLOW
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* STACK_MACROS_H */
|
||||
|
|
@ -1,33 +1,43 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _NNCASE_H
|
||||
#define _NNCASE_H
|
||||
|
||||
#include "kpu.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int nncase_load_kmodel(kpu_model_context_t *ctx, const uint8_t *buffer);
|
||||
int nncase_get_output(kpu_model_context_t *ctx, uint32_t index, uint8_t **data, size_t *size);
|
||||
void nncase_model_free(kpu_model_context_t *ctx);
|
||||
int nncase_run_kmodel(kpu_model_context_t *ctx, const uint8_t *src, dmac_channel_number_t dma_ch, kpu_done_callback_t done_callback, void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Core Synchronization
|
||||
|
||||
#ifndef CORE_SYNC_H
|
||||
#define CORE_SYNC_H
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CORE_SYNC_NONE,
|
||||
CORE_SYNC_ADD_TCB
|
||||
} core_sync_event_t;
|
||||
|
||||
void core_sync_request_context_switch(uint64_t core_id);
|
||||
void core_sync_complete_context_switch(uint64_t core_id);
|
||||
void core_sync_complete(uint64_t core_id);
|
||||
int core_sync_is_in_progress(uint64_t core_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CORE_SYNC_H */
|
|
@ -0,0 +1,734 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef CO_ROUTINE_H
|
||||
#define CO_ROUTINE_H
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
#error "include FreeRTOS.h must appear in source files before include croutine.h"
|
||||
#endif
|
||||
|
||||
#include "list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Used to hide the implementation of the co-routine control block. The
|
||||
control block structure however has to be included in the header due to
|
||||
the macro implementation of the co-routine functionality. */
|
||||
typedef void * CoRoutineHandle_t;
|
||||
|
||||
/* Defines the prototype to which co-routine functions must conform. */
|
||||
typedef void (*crCOROUTINE_CODE)( CoRoutineHandle_t, UBaseType_t );
|
||||
|
||||
typedef struct corCoRoutineControlBlock
|
||||
{
|
||||
crCOROUTINE_CODE pxCoRoutineFunction;
|
||||
ListItem_t xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
|
||||
ListItem_t xEventListItem; /*< List item used to place the CRCB in event lists. */
|
||||
UBaseType_t uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
|
||||
UBaseType_t uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
|
||||
uint16_t uxState; /*< Used internally by the co-routine implementation. */
|
||||
} CRCB_t; /* Co-routine control block. Note must be identical in size down to uxPriority with TCB_t. */
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
*<pre>
|
||||
BaseType_t xCoRoutineCreate(
|
||||
crCOROUTINE_CODE pxCoRoutineCode,
|
||||
UBaseType_t uxPriority,
|
||||
UBaseType_t uxIndex
|
||||
);</pre>
|
||||
*
|
||||
* Create a new co-routine and add it to the list of co-routines that are
|
||||
* ready to run.
|
||||
*
|
||||
* @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
|
||||
* functions require special syntax - see the co-routine section of the WEB
|
||||
* documentation for more information.
|
||||
*
|
||||
* @param uxPriority The priority with respect to other co-routines at which
|
||||
* the co-routine will run.
|
||||
*
|
||||
* @param uxIndex Used to distinguish between different co-routines that
|
||||
* execute the same function. See the example below and the co-routine section
|
||||
* of the WEB documentation for further information.
|
||||
*
|
||||
* @return pdPASS if the co-routine was successfully created and added to a ready
|
||||
* list, otherwise an error code defined with ProjDefs.h.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Co-routine to be created.
|
||||
void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||
// This may not be necessary for const variables.
|
||||
static const char cLedToFlash[ 2 ] = { 5, 6 };
|
||||
static const TickType_t uxFlashRates[ 2 ] = { 200, 400 };
|
||||
|
||||
// Must start every co-routine with a call to crSTART();
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// This co-routine just delays for a fixed period, then toggles
|
||||
// an LED. Two co-routines are created using this function, so
|
||||
// the uxIndex parameter is used to tell the co-routine which
|
||||
// LED to flash and how int32_t to delay. This assumes xQueue has
|
||||
// already been created.
|
||||
vParTestToggleLED( cLedToFlash[ uxIndex ] );
|
||||
crDELAY( xHandle, uxFlashRates[ uxIndex ] );
|
||||
}
|
||||
|
||||
// Must end every co-routine with a call to crEND();
|
||||
crEND();
|
||||
}
|
||||
|
||||
// Function that creates two co-routines.
|
||||
void vOtherFunction( void )
|
||||
{
|
||||
uint8_t ucParameterToPass;
|
||||
TaskHandle_t xHandle;
|
||||
|
||||
// Create two co-routines at priority 0. The first is given index 0
|
||||
// so (from the code above) toggles LED 5 every 200 ticks. The second
|
||||
// is given index 1 so toggles LED 6 every 400 ticks.
|
||||
for( uxIndex = 0; uxIndex < 2; uxIndex++ )
|
||||
{
|
||||
xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xCoRoutineCreate xCoRoutineCreate
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPriority, UBaseType_t uxIndex );
|
||||
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
*<pre>
|
||||
void vCoRoutineSchedule( void );</pre>
|
||||
*
|
||||
* Run a co-routine.
|
||||
*
|
||||
* vCoRoutineSchedule() executes the highest priority co-routine that is able
|
||||
* to run. The co-routine will execute until it either blocks, yields or is
|
||||
* preempted by a task. Co-routines execute cooperatively so one
|
||||
* co-routine cannot be preempted by another, but can be preempted by a task.
|
||||
*
|
||||
* If an application comprises of both tasks and co-routines then
|
||||
* vCoRoutineSchedule should be called from the idle task (in an idle task
|
||||
* hook).
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// This idle task hook will schedule a co-routine each time it is called.
|
||||
// The rest of the idle task will execute between co-routine calls.
|
||||
void vApplicationIdleHook( void )
|
||||
{
|
||||
vCoRoutineSchedule();
|
||||
}
|
||||
|
||||
// Alternatively, if you do not require any other part of the idle task to
|
||||
// execute, the idle task hook can call vCoRoutineScheduler() within an
|
||||
// infinite loop.
|
||||
void vApplicationIdleHook( void )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
vCoRoutineSchedule();
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup vCoRoutineSchedule vCoRoutineSchedule
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
void vCoRoutineSchedule( void );
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
* <pre>
|
||||
crSTART( CoRoutineHandle_t xHandle );</pre>
|
||||
*
|
||||
* This macro MUST always be called at the start of a co-routine function.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Co-routine to be created.
|
||||
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||
static int32_t ulAVariable;
|
||||
|
||||
// Must start every co-routine with a call to crSTART();
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Co-routine functionality goes here.
|
||||
}
|
||||
|
||||
// Must end every co-routine with a call to crEND();
|
||||
crEND();
|
||||
}</pre>
|
||||
* \defgroup crSTART crSTART
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crSTART( pxCRCB ) switch( ( ( CRCB_t * )( pxCRCB ) )->uxState ) { case 0:
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
* <pre>
|
||||
crEND();</pre>
|
||||
*
|
||||
* This macro MUST always be called at the end of a co-routine function.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Co-routine to be created.
|
||||
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||
static int32_t ulAVariable;
|
||||
|
||||
// Must start every co-routine with a call to crSTART();
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Co-routine functionality goes here.
|
||||
}
|
||||
|
||||
// Must end every co-routine with a call to crEND();
|
||||
crEND();
|
||||
}</pre>
|
||||
* \defgroup crSTART crSTART
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crEND() }
|
||||
|
||||
/*
|
||||
* These macros are intended for internal use by the co-routine implementation
|
||||
* only. The macros should not be used directly by application writers.
|
||||
*/
|
||||
#define crSET_STATE0( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
|
||||
#define crSET_STATE1( xHandle ) ( ( CRCB_t * )( xHandle ) )->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
*<pre>
|
||||
crDELAY( CoRoutineHandle_t xHandle, TickType_t xTicksToDelay );</pre>
|
||||
*
|
||||
* Delay a co-routine for a fixed period of time.
|
||||
*
|
||||
* crDELAY can only be called from the co-routine function itself - not
|
||||
* from within a function called by the co-routine function. This is because
|
||||
* co-routines do not maintain their own stack.
|
||||
*
|
||||
* @param xHandle The handle of the co-routine to delay. This is the xHandle
|
||||
* parameter of the co-routine function.
|
||||
*
|
||||
* @param xTickToDelay The number of ticks that the co-routine should delay
|
||||
* for. The actual amount of time this equates to is defined by
|
||||
* configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_PERIOD_MS
|
||||
* can be used to convert ticks to milliseconds.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Co-routine to be created.
|
||||
void vACoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||
// This may not be necessary for const variables.
|
||||
// We are to delay for 200ms.
|
||||
static const xTickType xDelayTime = 200 / portTICK_PERIOD_MS;
|
||||
|
||||
// Must start every co-routine with a call to crSTART();
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Delay for 200ms.
|
||||
crDELAY( xHandle, xDelayTime );
|
||||
|
||||
// Do something here.
|
||||
}
|
||||
|
||||
// Must end every co-routine with a call to crEND();
|
||||
crEND();
|
||||
}</pre>
|
||||
* \defgroup crDELAY crDELAY
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crDELAY( xHandle, xTicksToDelay ) \
|
||||
if( ( xTicksToDelay ) > 0 ) \
|
||||
{ \
|
||||
vCoRoutineAddToDelayedList( ( xTicksToDelay ), NULL ); \
|
||||
} \
|
||||
crSET_STATE0( ( xHandle ) );
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
crQUEUE_SEND(
|
||||
CoRoutineHandle_t xHandle,
|
||||
QueueHandle_t pxQueue,
|
||||
void *pvItemToQueue,
|
||||
TickType_t xTicksToWait,
|
||||
BaseType_t *pxResult
|
||||
)</pre>
|
||||
*
|
||||
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
|
||||
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
|
||||
*
|
||||
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
|
||||
* xQueueSend() and xQueueReceive() can only be used from tasks.
|
||||
*
|
||||
* crQUEUE_SEND can only be called from the co-routine function itself - not
|
||||
* from within a function called by the co-routine function. This is because
|
||||
* co-routines do not maintain their own stack.
|
||||
*
|
||||
* See the co-routine section of the WEB documentation for information on
|
||||
* passing data between tasks and co-routines and between ISR's and
|
||||
* co-routines.
|
||||
*
|
||||
* @param xHandle The handle of the calling co-routine. This is the xHandle
|
||||
* parameter of the co-routine function.
|
||||
*
|
||||
* @param pxQueue The handle of the queue on which the data will be posted.
|
||||
* The handle is obtained as the return value when the queue is created using
|
||||
* the xQueueCreate() API function.
|
||||
*
|
||||
* @param pvItemToQueue A pointer to the data being posted onto the queue.
|
||||
* The number of bytes of each queued item is specified when the queue is
|
||||
* created. This number of bytes is copied from pvItemToQueue into the queue
|
||||
* itself.
|
||||
*
|
||||
* @param xTickToDelay The number of ticks that the co-routine should block
|
||||
* to wait for space to become available on the queue, should space not be
|
||||
* available immediately. The actual amount of time this equates to is defined
|
||||
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
|
||||
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see example
|
||||
* below).
|
||||
*
|
||||
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
|
||||
* data was successfully posted onto the queue, otherwise it will be set to an
|
||||
* error defined within ProjDefs.h.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Co-routine function that blocks for a fixed period then posts a number onto
|
||||
// a queue.
|
||||
static void prvCoRoutineFlashTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||
static BaseType_t xNumberToPost = 0;
|
||||
static BaseType_t xResult;
|
||||
|
||||
// Co-routines must begin with a call to crSTART().
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// This assumes the queue has already been created.
|
||||
crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
// The message was not posted!
|
||||
}
|
||||
|
||||
// Increment the number to be posted onto the queue.
|
||||
xNumberToPost++;
|
||||
|
||||
// Delay for 100 ticks.
|
||||
crDELAY( xHandle, 100 );
|
||||
}
|
||||
|
||||
// Co-routines must end with a call to crEND().
|
||||
crEND();
|
||||
}</pre>
|
||||
* \defgroup crQUEUE_SEND crQUEUE_SEND
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
|
||||
{ \
|
||||
*( pxResult ) = xQueueCRSend( ( pxQueue) , ( pvItemToQueue) , ( xTicksToWait ) ); \
|
||||
if( *( pxResult ) == errQUEUE_BLOCKED ) \
|
||||
{ \
|
||||
crSET_STATE0( ( xHandle ) ); \
|
||||
*pxResult = xQueueCRSend( ( pxQueue ), ( pvItemToQueue ), 0 ); \
|
||||
} \
|
||||
if( *pxResult == errQUEUE_YIELD ) \
|
||||
{ \
|
||||
crSET_STATE1( ( xHandle ) ); \
|
||||
*pxResult = pdPASS; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
* <pre>
|
||||
crQUEUE_RECEIVE(
|
||||
CoRoutineHandle_t xHandle,
|
||||
QueueHandle_t pxQueue,
|
||||
void *pvBuffer,
|
||||
TickType_t xTicksToWait,
|
||||
BaseType_t *pxResult
|
||||
)</pre>
|
||||
*
|
||||
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
|
||||
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
|
||||
*
|
||||
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
|
||||
* xQueueSend() and xQueueReceive() can only be used from tasks.
|
||||
*
|
||||
* crQUEUE_RECEIVE can only be called from the co-routine function itself - not
|
||||
* from within a function called by the co-routine function. This is because
|
||||
* co-routines do not maintain their own stack.
|
||||
*
|
||||
* See the co-routine section of the WEB documentation for information on
|
||||
* passing data between tasks and co-routines and between ISR's and
|
||||
* co-routines.
|
||||
*
|
||||
* @param xHandle The handle of the calling co-routine. This is the xHandle
|
||||
* parameter of the co-routine function.
|
||||
*
|
||||
* @param pxQueue The handle of the queue from which the data will be received.
|
||||
* The handle is obtained as the return value when the queue is created using
|
||||
* the xQueueCreate() API function.
|
||||
*
|
||||
* @param pvBuffer The buffer into which the received item is to be copied.
|
||||
* The number of bytes of each queued item is specified when the queue is
|
||||
* created. This number of bytes is copied into pvBuffer.
|
||||
*
|
||||
* @param xTickToDelay The number of ticks that the co-routine should block
|
||||
* to wait for data to become available from the queue, should data not be
|
||||
* available immediately. The actual amount of time this equates to is defined
|
||||
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
|
||||
* portTICK_PERIOD_MS can be used to convert ticks to milliseconds (see the
|
||||
* crQUEUE_SEND example).
|
||||
*
|
||||
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
|
||||
* data was successfully retrieved from the queue, otherwise it will be set to
|
||||
* an error code as defined within ProjDefs.h.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// A co-routine receives the number of an LED to flash from a queue. It
|
||||
// blocks on the queue until the number is received.
|
||||
static void prvCoRoutineFlashWorkTask( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
|
||||
static BaseType_t xResult;
|
||||
static UBaseType_t uxLEDToFlash;
|
||||
|
||||
// All co-routines must start with a call to crSTART().
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Wait for data to become available on the queue.
|
||||
crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// We received the LED to flash - flash it!
|
||||
vParTestToggleLED( uxLEDToFlash );
|
||||
}
|
||||
}
|
||||
|
||||
crEND();
|
||||
}</pre>
|
||||
* \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
|
||||
{ \
|
||||
*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), ( xTicksToWait ) ); \
|
||||
if( *( pxResult ) == errQUEUE_BLOCKED ) \
|
||||
{ \
|
||||
crSET_STATE0( ( xHandle ) ); \
|
||||
*( pxResult ) = xQueueCRReceive( ( pxQueue) , ( pvBuffer ), 0 ); \
|
||||
} \
|
||||
if( *( pxResult ) == errQUEUE_YIELD ) \
|
||||
{ \
|
||||
crSET_STATE1( ( xHandle ) ); \
|
||||
*( pxResult ) = pdPASS; \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
* <pre>
|
||||
crQUEUE_SEND_FROM_ISR(
|
||||
QueueHandle_t pxQueue,
|
||||
void *pvItemToQueue,
|
||||
BaseType_t xCoRoutinePreviouslyWoken
|
||||
)</pre>
|
||||
*
|
||||
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
|
||||
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
|
||||
* functions used by tasks.
|
||||
*
|
||||
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
|
||||
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
|
||||
* xQueueReceiveFromISR() can only be used to pass data between a task and and
|
||||
* ISR.
|
||||
*
|
||||
* crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
|
||||
* that is being used from within a co-routine.
|
||||
*
|
||||
* See the co-routine section of the WEB documentation for information on
|
||||
* passing data between tasks and co-routines and between ISR's and
|
||||
* co-routines.
|
||||
*
|
||||
* @param xQueue The handle to the queue on which the item is to be posted.
|
||||
*
|
||||
* @param pvItemToQueue A pointer to the item that is to be placed on the
|
||||
* queue. The size of the items the queue will hold was defined when the
|
||||
* queue was created, so this many bytes will be copied from pvItemToQueue
|
||||
* into the queue storage area.
|
||||
*
|
||||
* @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
|
||||
* the same queue multiple times from a single interrupt. The first call
|
||||
* should always pass in pdFALSE. Subsequent calls should pass in
|
||||
* the value returned from the previous call.
|
||||
*
|
||||
* @return pdTRUE if a co-routine was woken by posting onto the queue. This is
|
||||
* used by the ISR to determine if a context switch may be required following
|
||||
* the ISR.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// A co-routine that blocks on a queue waiting for characters to be received.
|
||||
static void vReceivingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
char cRxedChar;
|
||||
BaseType_t xResult;
|
||||
|
||||
// All co-routines must start with a call to crSTART().
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Wait for data to become available on the queue. This assumes the
|
||||
// queue xCommsRxQueue has already been created!
|
||||
crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||
|
||||
// Was a character received?
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// Process the character here.
|
||||
}
|
||||
}
|
||||
|
||||
// All co-routines must end with a call to crEND().
|
||||
crEND();
|
||||
}
|
||||
|
||||
// An ISR that uses a queue to send characters received on a serial port to
|
||||
// a co-routine.
|
||||
void vUART_ISR( void )
|
||||
{
|
||||
char cRxedChar;
|
||||
BaseType_t xCRWokenByPost = pdFALSE;
|
||||
|
||||
// We loop around reading characters until there are none left in the UART.
|
||||
while( UART_RX_REG_NOT_EMPTY() )
|
||||
{
|
||||
// Obtain the character from the UART.
|
||||
cRxedChar = UART_RX_REG;
|
||||
|
||||
// Post the character onto a queue. xCRWokenByPost will be pdFALSE
|
||||
// the first time around the loop. If the post causes a co-routine
|
||||
// to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
|
||||
// In this manner we can ensure that if more than one co-routine is
|
||||
// blocked on the queue only one is woken by this ISR no matter how
|
||||
// many characters are posted to the queue.
|
||||
xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
|
||||
}
|
||||
}</pre>
|
||||
* \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( ( pxQueue ), ( pvItemToQueue ), ( xCoRoutinePreviouslyWoken ) )
|
||||
|
||||
|
||||
/**
|
||||
* croutine. h
|
||||
* <pre>
|
||||
crQUEUE_SEND_FROM_ISR(
|
||||
QueueHandle_t pxQueue,
|
||||
void *pvBuffer,
|
||||
BaseType_t * pxCoRoutineWoken
|
||||
)</pre>
|
||||
*
|
||||
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
|
||||
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
|
||||
* functions used by tasks.
|
||||
*
|
||||
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
|
||||
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
|
||||
* xQueueReceiveFromISR() can only be used to pass data between a task and and
|
||||
* ISR.
|
||||
*
|
||||
* crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
|
||||
* from a queue that is being used from within a co-routine (a co-routine
|
||||
* posted to the queue).
|
||||
*
|
||||
* See the co-routine section of the WEB documentation for information on
|
||||
* passing data between tasks and co-routines and between ISR's and
|
||||
* co-routines.
|
||||
*
|
||||
* @param xQueue The handle to the queue on which the item is to be posted.
|
||||
*
|
||||
* @param pvBuffer A pointer to a buffer into which the received item will be
|
||||
* placed. The size of the items the queue will hold was defined when the
|
||||
* queue was created, so this many bytes will be copied from the queue into
|
||||
* pvBuffer.
|
||||
*
|
||||
* @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
|
||||
* available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
|
||||
* co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
|
||||
* *pxCoRoutineWoken will remain unchanged.
|
||||
*
|
||||
* @return pdTRUE an item was successfully received from the queue, otherwise
|
||||
* pdFALSE.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// A co-routine that posts a character to a queue then blocks for a fixed
|
||||
// period. The character is incremented each time.
|
||||
static void vSendingCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
|
||||
{
|
||||
// cChar holds its value while this co-routine is blocked and must therefore
|
||||
// be declared static.
|
||||
static char cCharToTx = 'a';
|
||||
BaseType_t xResult;
|
||||
|
||||
// All co-routines must start with a call to crSTART().
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Send the next character to the queue.
|
||||
crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
|
||||
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// The character was successfully posted to the queue.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Could not post the character to the queue.
|
||||
}
|
||||
|
||||
// Enable the UART Tx interrupt to cause an interrupt in this
|
||||
// hypothetical UART. The interrupt will obtain the character
|
||||
// from the queue and send it.
|
||||
ENABLE_RX_INTERRUPT();
|
||||
|
||||
// Increment to the next character then block for a fixed period.
|
||||
// cCharToTx will maintain its value across the delay as it is
|
||||
// declared static.
|
||||
cCharToTx++;
|
||||
if( cCharToTx > 'x' )
|
||||
{
|
||||
cCharToTx = 'a';
|
||||
}
|
||||
crDELAY( 100 );
|
||||
}
|
||||
|
||||
// All co-routines must end with a call to crEND().
|
||||
crEND();
|
||||
}
|
||||
|
||||
// An ISR that uses a queue to receive characters to send on a UART.
|
||||
void vUART_ISR( void )
|
||||
{
|
||||
char cCharToTx;
|
||||
BaseType_t xCRWokenByPost = pdFALSE;
|
||||
|
||||
while( UART_TX_REG_EMPTY() )
|
||||
{
|
||||
// Are there any characters in the queue waiting to be sent?
|
||||
// xCRWokenByPost will automatically be set to pdTRUE if a co-routine
|
||||
// is woken by the post - ensuring that only a single co-routine is
|
||||
// woken no matter how many times we go around this loop.
|
||||
if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
|
||||
{
|
||||
SEND_CHARACTER( cCharToTx );
|
||||
}
|
||||
}
|
||||
}</pre>
|
||||
* \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( ( pxQueue ), ( pvBuffer ), ( pxCoRoutineWoken ) )
|
||||
|
||||
/*
|
||||
* This function is intended for internal use by the co-routine macros only.
|
||||
* The macro nature of the co-routine implementation requires that the
|
||||
* prototype appears here. The function should not be used by application
|
||||
* writers.
|
||||
*
|
||||
* Removes the current co-routine from its ready list and places it in the
|
||||
* appropriate delayed list.
|
||||
*/
|
||||
void vCoRoutineAddToDelayedList( TickType_t xTicksToDelay, List_t *pxEventList );
|
||||
|
||||
/*
|
||||
* This function is intended for internal use by the queue implementation only.
|
||||
* The function should not be used by application writers.
|
||||
*
|
||||
* Removes the highest priority co-routine from the event list and places it in
|
||||
* the pending ready list.
|
||||
*/
|
||||
BaseType_t xCoRoutineRemoveFromEventList( const List_t *pxEventList );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CO_ROUTINE_H */
|
|
@ -0,0 +1,770 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef EVENT_GROUPS_H
|
||||
#define EVENT_GROUPS_H
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
#error "include FreeRTOS.h" must appear in source files before "include event_groups.h"
|
||||
#endif
|
||||
|
||||
/* FreeRTOS includes. */
|
||||
#include "timers.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An event group is a collection of bits to which an application can assign a
|
||||
* meaning. For example, an application may create an event group to convey
|
||||
* the status of various CAN bus related events in which bit 0 might mean "A CAN
|
||||
* message has been received and is ready for processing", bit 1 might mean "The
|
||||
* application has queued a message that is ready for sending onto the CAN
|
||||
* network", and bit 2 might mean "It is time to send a SYNC message onto the
|
||||
* CAN network" etc. A task can then test the bit values to see which events
|
||||
* are active, and optionally enter the Blocked state to wait for a specified
|
||||
* bit or a group of specified bits to be active. To continue the CAN bus
|
||||
* example, a CAN controlling task can enter the Blocked state (and therefore
|
||||
* not consume any processing time) until either bit 0, bit 1 or bit 2 are
|
||||
* active, at which time the bit that was actually active would inform the task
|
||||
* which action it had to take (process a received message, send a message, or
|
||||
* send a SYNC).
|
||||
*
|
||||
* The event groups implementation contains intelligence to avoid race
|
||||
* conditions that would otherwise occur were an application to use a simple
|
||||
* variable for the same purpose. This is particularly important with respect
|
||||
* to when a bit within an event group is to be cleared, and when bits have to
|
||||
* be set and then tested atomically - as is the case where event groups are
|
||||
* used to create a synchronisation point between multiple tasks (a
|
||||
* 'rendezvous').
|
||||
*
|
||||
* \defgroup EventGroup
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*
|
||||
* Type by which event groups are referenced. For example, a call to
|
||||
* xEventGroupCreate() returns an EventGroupHandle_t variable that can then
|
||||
* be used as a parameter to other event group functions.
|
||||
*
|
||||
* \defgroup EventGroupHandle_t EventGroupHandle_t
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
typedef void * EventGroupHandle_t;
|
||||
|
||||
/*
|
||||
* The type that holds event bits always matches TickType_t - therefore the
|
||||
* number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
|
||||
* 32 bits if set to 0.
|
||||
*
|
||||
* \defgroup EventBits_t EventBits_t
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
typedef TickType_t EventBits_t;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventGroupHandle_t xEventGroupCreate( void );
|
||||
</pre>
|
||||
*
|
||||
* Create a new event group.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||
* block of memory, in which the event group's structure is stored. If an event
|
||||
* groups is created using xEventGropuCreate() then the required memory is
|
||||
* automatically dynamically allocated inside the xEventGroupCreate() function.
|
||||
* (see http://www.freertos.org/a00111.html). If an event group is created
|
||||
* using xEventGropuCreateStatic() then the application writer must instead
|
||||
* provide the memory that will get used by the event group.
|
||||
* xEventGroupCreateStatic() therefore allows an event group to be created
|
||||
* without using any dynamic memory allocation.
|
||||
*
|
||||
* Although event groups are not related to ticks, for internal implementation
|
||||
* reasons the number of bits available for use in an event group is dependent
|
||||
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
|
||||
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
|
||||
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
|
||||
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
|
||||
* event bits within an event group.
|
||||
*
|
||||
* @return If the event group was created then a handle to the event group is
|
||||
* returned. If there was insufficient FreeRTOS heap available to create the
|
||||
* event group then NULL is returned. See http://www.freertos.org/a00111.html
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Declare a variable to hold the created event group.
|
||||
EventGroupHandle_t xCreatedEventGroup;
|
||||
|
||||
// Attempt to create the event group.
|
||||
xCreatedEventGroup = xEventGroupCreate();
|
||||
|
||||
// Was the event group created successfully?
|
||||
if( xCreatedEventGroup == NULL )
|
||||
{
|
||||
// The event group was not created because there was insufficient
|
||||
// FreeRTOS heap available.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The event group was created.
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupCreate xEventGroupCreate
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
EventGroupHandle_t xEventGroupCreate( void ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Create a new event group.
|
||||
*
|
||||
* Internally, within the FreeRTOS implementation, event groups use a [small]
|
||||
* block of memory, in which the event group's structure is stored. If an event
|
||||
* groups is created using xEventGropuCreate() then the required memory is
|
||||
* automatically dynamically allocated inside the xEventGroupCreate() function.
|
||||
* (see http://www.freertos.org/a00111.html). If an event group is created
|
||||
* using xEventGropuCreateStatic() then the application writer must instead
|
||||
* provide the memory that will get used by the event group.
|
||||
* xEventGroupCreateStatic() therefore allows an event group to be created
|
||||
* without using any dynamic memory allocation.
|
||||
*
|
||||
* Although event groups are not related to ticks, for internal implementation
|
||||
* reasons the number of bits available for use in an event group is dependent
|
||||
* on the configUSE_16_BIT_TICKS setting in FreeRTOSConfig.h. If
|
||||
* configUSE_16_BIT_TICKS is 1 then each event group contains 8 usable bits (bit
|
||||
* 0 to bit 7). If configUSE_16_BIT_TICKS is set to 0 then each event group has
|
||||
* 24 usable bits (bit 0 to bit 23). The EventBits_t type is used to store
|
||||
* event bits within an event group.
|
||||
*
|
||||
* @param pxEventGroupBuffer pxEventGroupBuffer must point to a variable of type
|
||||
* StaticEventGroup_t, which will be then be used to hold the event group's data
|
||||
* structures, removing the need for the memory to be allocated dynamically.
|
||||
*
|
||||
* @return If the event group was created then a handle to the event group is
|
||||
* returned. If pxEventGroupBuffer was NULL then NULL is returned.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// StaticEventGroup_t is a publicly accessible structure that has the same
|
||||
// size and alignment requirements as the real event group structure. It is
|
||||
// provided as a mechanism for applications to know the size of the event
|
||||
// group (which is dependent on the architecture and configuration file
|
||||
// settings) without breaking the strict data hiding policy by exposing the
|
||||
// real event group internals. This StaticEventGroup_t variable is passed
|
||||
// into the xSemaphoreCreateEventGroupStatic() function and is used to store
|
||||
// the event group's data structures
|
||||
StaticEventGroup_t xEventGroupBuffer;
|
||||
|
||||
// Create the event group without dynamically allocating any memory.
|
||||
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
|
||||
</pre>
|
||||
*/
|
||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
const BaseType_t xClearOnExit,
|
||||
const BaseType_t xWaitForAllBits,
|
||||
const TickType_t xTicksToWait );
|
||||
</pre>
|
||||
*
|
||||
* [Potentially] block to wait for one or more bits to be set within a
|
||||
* previously created event group.
|
||||
*
|
||||
* This function cannot be called from an interrupt.
|
||||
*
|
||||
* @param xEventGroup The event group in which the bits are being tested. The
|
||||
* event group must have previously been created using a call to
|
||||
* xEventGroupCreate().
|
||||
*
|
||||
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
|
||||
* inside the event group. For example, to wait for bit 0 and/or bit 2 set
|
||||
* uxBitsToWaitFor to 0x05. To wait for bits 0 and/or bit 1 and/or bit 2 set
|
||||
* uxBitsToWaitFor to 0x07. Etc.
|
||||
*
|
||||
* @param xClearOnExit If xClearOnExit is set to pdTRUE then any bits within
|
||||
* uxBitsToWaitFor that are set within the event group will be cleared before
|
||||
* xEventGroupWaitBits() returns if the wait condition was met (if the function
|
||||
* returns for a reason other than a timeout). If xClearOnExit is set to
|
||||
* pdFALSE then the bits set in the event group are not altered when the call to
|
||||
* xEventGroupWaitBits() returns.
|
||||
*
|
||||
* @param xWaitForAllBits If xWaitForAllBits is set to pdTRUE then
|
||||
* xEventGroupWaitBits() will return when either all the bits in uxBitsToWaitFor
|
||||
* are set or the specified block time expires. If xWaitForAllBits is set to
|
||||
* pdFALSE then xEventGroupWaitBits() will return when any one of the bits set
|
||||
* in uxBitsToWaitFor is set or the specified block time expires. The block
|
||||
* time is specified by the xTicksToWait parameter.
|
||||
*
|
||||
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
|
||||
* for one/all (depending on the xWaitForAllBits value) of the bits specified by
|
||||
* uxBitsToWaitFor to become set.
|
||||
*
|
||||
* @return The value of the event group at the time either the bits being waited
|
||||
* for became set, or the block time expired. Test the return value to know
|
||||
* which bits were set. If xEventGroupWaitBits() returned because its timeout
|
||||
* expired then not all the bits being waited for will be set. If
|
||||
* xEventGroupWaitBits() returned because the bits it was waiting for were set
|
||||
* then the returned value is the event group value before any bits were
|
||||
* automatically cleared in the case that xClearOnExit parameter was set to
|
||||
* pdTRUE.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
void aFunction( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||
|
||||
// Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
|
||||
// the event group. Clear the bits before exiting.
|
||||
uxBits = xEventGroupWaitBits(
|
||||
xEventGroup, // The event group being tested.
|
||||
BIT_0 | BIT_4, // The bits within the event group to wait for.
|
||||
pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
|
||||
pdFALSE, // Don't wait for both bits, either bit will do.
|
||||
xTicksToWait ); // Wait a maximum of 100ms for either bit to be set.
|
||||
|
||||
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
{
|
||||
// xEventGroupWaitBits() returned because both bits were set.
|
||||
}
|
||||
else if( ( uxBits & BIT_0 ) != 0 )
|
||||
{
|
||||
// xEventGroupWaitBits() returned because just BIT_0 was set.
|
||||
}
|
||||
else if( ( uxBits & BIT_4 ) != 0 )
|
||||
{
|
||||
// xEventGroupWaitBits() returned because just BIT_4 was set.
|
||||
}
|
||||
else
|
||||
{
|
||||
// xEventGroupWaitBits() returned because xTicksToWait ticks passed
|
||||
// without either BIT_0 or BIT_4 becoming set.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupWaitBits xEventGroupWaitBits
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
|
||||
</pre>
|
||||
*
|
||||
* Clear bits within an event group. This function cannot be called from an
|
||||
* interrupt.
|
||||
*
|
||||
* @param xEventGroup The event group in which the bits are to be cleared.
|
||||
*
|
||||
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear
|
||||
* in the event group. For example, to clear bit 3 only, set uxBitsToClear to
|
||||
* 0x08. To clear bit 3 and bit 0 set uxBitsToClear to 0x09.
|
||||
*
|
||||
* @return The value of the event group before the specified bits were cleared.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
void aFunction( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
|
||||
// Clear bit 0 and bit 4 in xEventGroup.
|
||||
uxBits = xEventGroupClearBits(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 );// The bits being cleared.
|
||||
|
||||
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
{
|
||||
// Both bit 0 and bit 4 were set before xEventGroupClearBits() was
|
||||
// called. Both will now be clear (not set).
|
||||
}
|
||||
else if( ( uxBits & BIT_0 ) != 0 )
|
||||
{
|
||||
// Bit 0 was set before xEventGroupClearBits() was called. It will
|
||||
// now be clear.
|
||||
}
|
||||
else if( ( uxBits & BIT_4 ) != 0 )
|
||||
{
|
||||
// Bit 4 was set before xEventGroupClearBits() was called. It will
|
||||
// now be clear.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither bit 0 nor bit 4 were set in the first place.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupClearBits xEventGroupClearBits
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||
</pre>
|
||||
*
|
||||
* A version of xEventGroupClearBits() that can be called from an interrupt.
|
||||
*
|
||||
* Setting bits in an event group is not a deterministic operation because there
|
||||
* are an unknown number of tasks that may be waiting for the bit or bits being
|
||||
* set. FreeRTOS does not allow nondeterministic operations to be performed
|
||||
* while interrupts are disabled, so protects event groups that are accessed
|
||||
* from tasks by suspending the scheduler rather than disabling interrupts. As
|
||||
* a result event groups cannot be accessed directly from an interrupt service
|
||||
* routine. Therefore xEventGroupClearBitsFromISR() sends a message to the
|
||||
* timer task to have the clear operation performed in the context of the timer
|
||||
* task.
|
||||
*
|
||||
* @param xEventGroup The event group in which the bits are to be cleared.
|
||||
*
|
||||
* @param uxBitsToClear A bitwise value that indicates the bit or bits to clear.
|
||||
* For example, to clear bit 3 only, set uxBitsToClear to 0x08. To clear bit 3
|
||||
* and bit 0 set uxBitsToClear to 0x09.
|
||||
*
|
||||
* @return If the request to execute the function was posted successfully then
|
||||
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
|
||||
* if the timer service queue was full.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
// An event group which it is assumed has already been created by a call to
|
||||
// xEventGroupCreate().
|
||||
EventGroupHandle_t xEventGroup;
|
||||
|
||||
void anInterruptHandler( void )
|
||||
{
|
||||
// Clear bit 0 and bit 4 in xEventGroup.
|
||||
xResult = xEventGroupClearBitsFromISR(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 ); // The bits being set.
|
||||
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// The message was posted successfully.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupClearBitsFromISR xEventGroupClearBitsFromISR
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
|
||||
#else
|
||||
#define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||
</pre>
|
||||
*
|
||||
* Set bits within an event group.
|
||||
* This function cannot be called from an interrupt. xEventGroupSetBitsFromISR()
|
||||
* is a version that can be called from an interrupt.
|
||||
*
|
||||
* Setting bits in an event group will automatically unblock tasks that are
|
||||
* blocked waiting for the bits.
|
||||
*
|
||||
* @param xEventGroup The event group in which the bits are to be set.
|
||||
*
|
||||
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
|
||||
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
|
||||
* and bit 0 set uxBitsToSet to 0x09.
|
||||
*
|
||||
* @return The value of the event group at the time the call to
|
||||
* xEventGroupSetBits() returns. There are two reasons why the returned value
|
||||
* might have the bits specified by the uxBitsToSet parameter cleared. First,
|
||||
* if setting a bit results in a task that was waiting for the bit leaving the
|
||||
* blocked state then it is possible the bit will be cleared automatically
|
||||
* (see the xClearBitOnExit parameter of xEventGroupWaitBits()). Second, any
|
||||
* unblocked (or otherwise Ready state) task that has a priority above that of
|
||||
* the task that called xEventGroupSetBits() will execute and may change the
|
||||
* event group value before the call to xEventGroupSetBits() returns.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
void aFunction( EventGroupHandle_t xEventGroup )
|
||||
{
|
||||
EventBits_t uxBits;
|
||||
|
||||
// Set bit 0 and bit 4 in xEventGroup.
|
||||
uxBits = xEventGroupSetBits(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 );// The bits being set.
|
||||
|
||||
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
|
||||
{
|
||||
// Both bit 0 and bit 4 remained set when the function returned.
|
||||
}
|
||||
else if( ( uxBits & BIT_0 ) != 0 )
|
||||
{
|
||||
// Bit 0 remained set when the function returned, but bit 4 was
|
||||
// cleared. It might be that bit 4 was cleared automatically as a
|
||||
// task that was waiting for bit 4 was removed from the Blocked
|
||||
// state.
|
||||
}
|
||||
else if( ( uxBits & BIT_4 ) != 0 )
|
||||
{
|
||||
// Bit 4 remained set when the function returned, but bit 0 was
|
||||
// cleared. It might be that bit 0 was cleared automatically as a
|
||||
// task that was waiting for bit 0 was removed from the Blocked
|
||||
// state.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neither bit 0 nor bit 4 remained set. It might be that a task
|
||||
// was waiting for both of the bits to be set, and the bits were
|
||||
// cleared as the task left the Blocked state.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupSetBits xEventGroupSetBits
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* A version of xEventGroupSetBits() that can be called from an interrupt.
|
||||
*
|
||||
* Setting bits in an event group is not a deterministic operation because there
|
||||
* are an unknown number of tasks that may be waiting for the bit or bits being
|
||||
* set. FreeRTOS does not allow nondeterministic operations to be performed in
|
||||
* interrupts or from critical sections. Therefore xEventGroupSetBitsFromISR()
|
||||
* sends a message to the timer task to have the set operation performed in the
|
||||
* context of the timer task - where a scheduler lock is used in place of a
|
||||
* critical section.
|
||||
*
|
||||
* @param xEventGroup The event group in which the bits are to be set.
|
||||
*
|
||||
* @param uxBitsToSet A bitwise value that indicates the bit or bits to set.
|
||||
* For example, to set bit 3 only, set uxBitsToSet to 0x08. To set bit 3
|
||||
* and bit 0 set uxBitsToSet to 0x09.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken As mentioned above, calling this function
|
||||
* will result in a message being sent to the timer daemon task. If the
|
||||
* priority of the timer daemon task is higher than the priority of the
|
||||
* currently running task (the task the interrupt interrupted) then
|
||||
* *pxHigherPriorityTaskWoken will be set to pdTRUE by
|
||||
* xEventGroupSetBitsFromISR(), indicating that a context switch should be
|
||||
* requested before the interrupt exits. For that reason
|
||||
* *pxHigherPriorityTaskWoken must be initialised to pdFALSE. See the
|
||||
* example code below.
|
||||
*
|
||||
* @return If the request to execute the function was posted successfully then
|
||||
* pdPASS is returned, otherwise pdFALSE is returned. pdFALSE will be returned
|
||||
* if the timer service queue was full.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
#define BIT_0 ( 1 << 0 )
|
||||
#define BIT_4 ( 1 << 4 )
|
||||
|
||||
// An event group which it is assumed has already been created by a call to
|
||||
// xEventGroupCreate().
|
||||
EventGroupHandle_t xEventGroup;
|
||||
|
||||
void anInterruptHandler( void )
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken, xResult;
|
||||
|
||||
// xHigherPriorityTaskWoken must be initialised to pdFALSE.
|
||||
xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
// Set bit 0 and bit 4 in xEventGroup.
|
||||
xResult = xEventGroupSetBitsFromISR(
|
||||
xEventGroup, // The event group being updated.
|
||||
BIT_0 | BIT_4 // The bits being set.
|
||||
&xHigherPriorityTaskWoken );
|
||||
|
||||
// Was the message posted successfully?
|
||||
if( xResult == pdPASS )
|
||||
{
|
||||
// If xHigherPriorityTaskWoken is now set to pdTRUE then a context
|
||||
// switch should be requested. The macro used is port specific and
|
||||
// will be either portYIELD_FROM_ISR() or portEND_SWITCHING_ISR() -
|
||||
// refer to the documentation page for the port being used.
|
||||
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xEventGroupSetBitsFromISR xEventGroupSetBitsFromISR
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||
#else
|
||||
#define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken )
|
||||
#endif
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
|
||||
const EventBits_t uxBitsToSet,
|
||||
const EventBits_t uxBitsToWaitFor,
|
||||
TickType_t xTicksToWait );
|
||||
</pre>
|
||||
*
|
||||
* Atomically set bits within an event group, then wait for a combination of
|
||||
* bits to be set within the same event group. This functionality is typically
|
||||
* used to synchronise multiple tasks, where each task has to wait for the other
|
||||
* tasks to reach a synchronisation point before proceeding.
|
||||
*
|
||||
* This function cannot be used from an interrupt.
|
||||
*
|
||||
* The function will return before its block time expires if the bits specified
|
||||
* by the uxBitsToWait parameter are set, or become set within that time. In
|
||||
* this case all the bits specified by uxBitsToWait will be automatically
|
||||
* cleared before the function returns.
|
||||
*
|
||||
* @param xEventGroup The event group in which the bits are being tested. The
|
||||
* event group must have previously been created using a call to
|
||||
* xEventGroupCreate().
|
||||
*
|
||||
* @param uxBitsToSet The bits to set in the event group before determining
|
||||
* if, and possibly waiting for, all the bits specified by the uxBitsToWait
|
||||
* parameter are set.
|
||||
*
|
||||
* @param uxBitsToWaitFor A bitwise value that indicates the bit or bits to test
|
||||
* inside the event group. For example, to wait for bit 0 and bit 2 set
|
||||
* uxBitsToWaitFor to 0x05. To wait for bits 0 and bit 1 and bit 2 set
|
||||
* uxBitsToWaitFor to 0x07. Etc.
|
||||
*
|
||||
* @param xTicksToWait The maximum amount of time (specified in 'ticks') to wait
|
||||
* for all of the bits specified by uxBitsToWaitFor to become set.
|
||||
*
|
||||
* @return The value of the event group at the time either the bits being waited
|
||||
* for became set, or the block time expired. Test the return value to know
|
||||
* which bits were set. If xEventGroupSync() returned because its timeout
|
||||
* expired then not all the bits being waited for will be set. If
|
||||
* xEventGroupSync() returned because all the bits it was waiting for were
|
||||
* set then the returned value is the event group value before any bits were
|
||||
* automatically cleared.
|
||||
*
|
||||
* Example usage:
|
||||
<pre>
|
||||
// Bits used by the three tasks.
|
||||
#define TASK_0_BIT ( 1 << 0 )
|
||||
#define TASK_1_BIT ( 1 << 1 )
|
||||
#define TASK_2_BIT ( 1 << 2 )
|
||||
|
||||
#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
|
||||
|
||||
// Use an event group to synchronise three tasks. It is assumed this event
|
||||
// group has already been created elsewhere.
|
||||
EventGroupHandle_t xEventBits;
|
||||
|
||||
void vTask0( void *pvParameters )
|
||||
{
|
||||
EventBits_t uxReturn;
|
||||
TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
// Perform task functionality here.
|
||||
|
||||
// Set bit 0 in the event flag to note this task has reached the
|
||||
// sync point. The other two tasks will set the other two bits defined
|
||||
// by ALL_SYNC_BITS. All three tasks have reached the synchronisation
|
||||
// point when all the ALL_SYNC_BITS are set. Wait a maximum of 100ms
|
||||
// for this to happen.
|
||||
uxReturn = xEventGroupSync( xEventBits, TASK_0_BIT, ALL_SYNC_BITS, xTicksToWait );
|
||||
|
||||
if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
|
||||
{
|
||||
// All three tasks reached the synchronisation point before the call
|
||||
// to xEventGroupSync() timed out.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vTask1( void *pvParameters )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
// Perform task functionality here.
|
||||
|
||||
// Set bit 1 in the event flag to note this task has reached the
|
||||
// synchronisation point. The other two tasks will set the other two
|
||||
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||
// indefinitely for this to happen.
|
||||
xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||
|
||||
// xEventGroupSync() was called with an indefinite block time, so
|
||||
// this task will only reach here if the syncrhonisation was made by all
|
||||
// three tasks, so there is no need to test the return value.
|
||||
}
|
||||
}
|
||||
|
||||
void vTask2( void *pvParameters )
|
||||
{
|
||||
for( ;; )
|
||||
{
|
||||
// Perform task functionality here.
|
||||
|
||||
// Set bit 2 in the event flag to note this task has reached the
|
||||
// synchronisation point. The other two tasks will set the other two
|
||||
// bits defined by ALL_SYNC_BITS. All three tasks have reached the
|
||||
// synchronisation point when all the ALL_SYNC_BITS are set. Wait
|
||||
// indefinitely for this to happen.
|
||||
xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );
|
||||
|
||||
// xEventGroupSync() was called with an indefinite block time, so
|
||||
// this task will only reach here if the syncrhonisation was made by all
|
||||
// three tasks, so there is no need to test the return value.
|
||||
}
|
||||
}
|
||||
|
||||
</pre>
|
||||
* \defgroup xEventGroupSync xEventGroupSync
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
|
||||
</pre>
|
||||
*
|
||||
* Returns the current value of the bits in an event group. This function
|
||||
* cannot be used from an interrupt.
|
||||
*
|
||||
* @param xEventGroup The event group being queried.
|
||||
*
|
||||
* @return The event group bits at the time xEventGroupGetBits() was called.
|
||||
*
|
||||
* \defgroup xEventGroupGetBits xEventGroupGetBits
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup );
|
||||
</pre>
|
||||
*
|
||||
* A version of xEventGroupGetBits() that can be called from an ISR.
|
||||
*
|
||||
* @param xEventGroup The event group being queried.
|
||||
*
|
||||
* @return The event group bits at the time xEventGroupGetBitsFromISR() was called.
|
||||
*
|
||||
* \defgroup xEventGroupGetBitsFromISR xEventGroupGetBitsFromISR
|
||||
* \ingroup EventGroup
|
||||
*/
|
||||
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* event_groups.h
|
||||
*<pre>
|
||||
void xEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
</pre>
|
||||
*
|
||||
* Delete an event group that was previously created by a call to
|
||||
* xEventGroupCreate(). Tasks that are blocked on the event group will be
|
||||
* unblocked and obtain 0 as the event group's value.
|
||||
*
|
||||
* @param xEventGroup The event group being deleted.
|
||||
*/
|
||||
void vEventGroupDelete( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/* For internal use only. */
|
||||
void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet ) PRIVILEGED_FUNCTION;
|
||||
void vEventGroupClearBitsCallback( void *pvEventGroup, const uint32_t ulBitsToClear ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
#if (configUSE_TRACE_FACILITY == 1)
|
||||
UBaseType_t uxEventGroupGetNumber( void* xEventGroup ) PRIVILEGED_FUNCTION;
|
||||
void vEventGroupSetNumber( void* xEventGroup, UBaseType_t uxEventGroupNumber ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EVENT_GROUPS_H */
|
||||
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the list implementation used by the scheduler. While it is tailored
|
||||
* heavily for the schedulers needs, it is also available for use by
|
||||
* application code.
|
||||
*
|
||||
* list_ts can only store pointers to list_item_ts. Each ListItem_t contains a
|
||||
* numeric value (xItemValue). Most of the time the lists are sorted in
|
||||
* descending item value order.
|
||||
*
|
||||
* Lists are created already containing one list item. The value of this
|
||||
* item is the maximum possible that can be stored, it is therefore always at
|
||||
* the end of the list and acts as a marker. The list member pxHead always
|
||||
* points to this marker - even though it is at the tail of the list. This
|
||||
* is because the tail contains a wrap back pointer to the true head of
|
||||
* the list.
|
||||
*
|
||||
* In addition to it's value, each list item contains a pointer to the next
|
||||
* item in the list (pxNext), a pointer to the list it is in (pxContainer)
|
||||
* and a pointer to back to the object that contains it. These later two
|
||||
* pointers are included for efficiency of list manipulation. There is
|
||||
* effectively a two way link between the object containing the list item and
|
||||
* the list item itself.
|
||||
*
|
||||
*
|
||||
* \page ListIntroduction List Implementation
|
||||
* \ingroup FreeRTOSIntro
|
||||
*/
|
||||
|
||||
#ifndef INC_FREERTOS_H
|
||||
#error FreeRTOS.h must be included before list.h
|
||||
#endif
|
||||
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
/*
|
||||
* The list structure members are modified from within interrupts, and therefore
|
||||
* by rights should be declared volatile. However, they are only modified in a
|
||||
* functionally atomic way (within critical sections of with the scheduler
|
||||
* suspended) and are either passed by reference into a function or indexed via
|
||||
* a volatile variable. Therefore, in all use cases tested so far, the volatile
|
||||
* qualifier can be omitted in order to provide a moderate performance
|
||||
* improvement without adversely affecting functional behaviour. The assembly
|
||||
* instructions generated by the IAR, ARM and GCC compilers when the respective
|
||||
* compiler's options were set for maximum optimisation has been inspected and
|
||||
* deemed to be as intended. That said, as compiler technology advances, and
|
||||
* especially if aggressive cross module optimisation is used (a use case that
|
||||
* has not been exercised to any great extend) then it is feasible that the
|
||||
* volatile qualifier will be needed for correct optimisation. It is expected
|
||||
* that a compiler removing essential code because, without the volatile
|
||||
* qualifier on the list structure members and with aggressive cross module
|
||||
* optimisation, the compiler deemed the code unnecessary will result in
|
||||
* complete and obvious failure of the scheduler. If this is ever experienced
|
||||
* then the volatile qualifier can be inserted in the relevant places within the
|
||||
* list structures by simply defining configLIST_VOLATILE to volatile in
|
||||
* FreeRTOSConfig.h (as per the example at the bottom of this comment block).
|
||||
* If configLIST_VOLATILE is not defined then the preprocessor directives below
|
||||
* will simply #define configLIST_VOLATILE away completely.
|
||||
*
|
||||
* To use volatile list structure members then add the following line to
|
||||
* FreeRTOSConfig.h (without the quotes):
|
||||
* "#define configLIST_VOLATILE volatile"
|
||||
*/
|
||||
#ifndef configLIST_VOLATILE
|
||||
#define configLIST_VOLATILE
|
||||
#endif /* configSUPPORT_CROSS_MODULE_OPTIMISATION */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Macros that can be used to place known values within the list structures,
|
||||
then check that the known values do not get corrupted during the execution of
|
||||
the application. These may catch the list data structures being overwritten in
|
||||
memory. They will not catch data errors caused by incorrect configuration or
|
||||
use of FreeRTOS.*/
|
||||
#if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
|
||||
/* Define the macros to do nothing. */
|
||||
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
|
||||
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
|
||||
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE
|
||||
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE
|
||||
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
|
||||
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )
|
||||
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
|
||||
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
|
||||
#define listTEST_LIST_ITEM_INTEGRITY( pxItem )
|
||||
#define listTEST_LIST_INTEGRITY( pxList )
|
||||
#else
|
||||
/* Define macros that add new members into the list structures. */
|
||||
#define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue1;
|
||||
#define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE TickType_t xListItemIntegrityValue2;
|
||||
#define listFIRST_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue1;
|
||||
#define listSECOND_LIST_INTEGRITY_CHECK_VALUE TickType_t xListIntegrityValue2;
|
||||
|
||||
/* Define macros that set the new structure members to known values. */
|
||||
#define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
|
||||
#define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ) ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
|
||||
#define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ) ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
|
||||
#define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ) ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
|
||||
|
||||
/* Define macros that will assert if one of the structure members does not
|
||||
contain its expected value. */
|
||||
#define listTEST_LIST_ITEM_INTEGRITY( pxItem ) configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
|
||||
#define listTEST_LIST_INTEGRITY( pxList ) configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
|
||||
#endif /* configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES */
|
||||
|
||||
|
||||
/*
|
||||
* Definition of the only type of object that a list can contain.
|
||||
*/
|
||||
struct xLIST_ITEM
|
||||
{
|
||||
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
|
||||
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
|
||||
void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
|
||||
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
};
|
||||
typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
|
||||
|
||||
struct xMINI_LIST_ITEM
|
||||
{
|
||||
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
configLIST_VOLATILE TickType_t xItemValue;
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
|
||||
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
|
||||
};
|
||||
typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||
|
||||
/*
|
||||
* Definition of the type of queue used by the scheduler.
|
||||
*/
|
||||
typedef struct xLIST
|
||||
{
|
||||
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
volatile UBaseType_t uxNumberOfItems;
|
||||
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
||||
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
||||
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
} List_t;
|
||||
|
||||
/*
|
||||
* Access macro to set the owner of a list item. The owner of a list item
|
||||
* is the object (usually a TCB) that contains the list item.
|
||||
*
|
||||
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
|
||||
|
||||
/*
|
||||
* Access macro to get the owner of a list item. The owner of a list item
|
||||
* is the object (usually a TCB) that contains the list item.
|
||||
*
|
||||
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_LIST_ITEM_OWNER( pxListItem ) ( ( pxListItem )->pvOwner )
|
||||
|
||||
/*
|
||||
* Access macro to set the value of the list item. In most cases the value is
|
||||
* used to sort the list in descending order.
|
||||
*
|
||||
* \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( ( pxListItem )->xItemValue = ( xValue ) )
|
||||
|
||||
/*
|
||||
* Access macro to retrieve the value of the list item. The value can
|
||||
* represent anything - for example the priority of a task, or the time at
|
||||
* which a task should be unblocked.
|
||||
*
|
||||
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
|
||||
|
||||
/*
|
||||
* Access macro to retrieve the value of the list item at the head of a given
|
||||
* list.
|
||||
*
|
||||
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext->xItemValue )
|
||||
|
||||
/*
|
||||
* Return the list item at the head of the list.
|
||||
*
|
||||
* \page listGET_HEAD_ENTRY listGET_HEAD_ENTRY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_HEAD_ENTRY( pxList ) ( ( ( pxList )->xListEnd ).pxNext )
|
||||
|
||||
/*
|
||||
* Return the list item at the head of the list.
|
||||
*
|
||||
* \page listGET_NEXT listGET_NEXT
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_NEXT( pxListItem ) ( ( pxListItem )->pxNext )
|
||||
|
||||
/*
|
||||
* Return the list item that marks the end of the list
|
||||
*
|
||||
* \page listGET_END_MARKER listGET_END_MARKER
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_END_MARKER( pxList ) ( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )
|
||||
|
||||
/*
|
||||
* Access macro to determine if a list contains any items. The macro will
|
||||
* only have the value true if the list is empty.
|
||||
*
|
||||
* \page listLIST_IS_EMPTY listLIST_IS_EMPTY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listLIST_IS_EMPTY( pxList ) ( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )
|
||||
|
||||
/*
|
||||
* Access macro to return the number of items in the list.
|
||||
*/
|
||||
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
|
||||
|
||||
/*
|
||||
* Access function to obtain the owner of the next entry in a list.
|
||||
*
|
||||
* The list member pxIndex is used to walk through a list. Calling
|
||||
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
|
||||
* and returns that entry's pxOwner parameter. Using multiple calls to this
|
||||
* function it is therefore possible to move through every item contained in
|
||||
* a list.
|
||||
*
|
||||
* The pxOwner parameter of a list item is a pointer to the object that owns
|
||||
* the list item. In the scheduler this is normally a task control block.
|
||||
* The pxOwner parameter effectively creates a two way link between the list
|
||||
* item and its owner.
|
||||
*
|
||||
* @param pxTCB pxTCB is set to the address of the owner of the next list item.
|
||||
* @param pxList The list from which the next item owner is to be returned.
|
||||
*
|
||||
* \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
|
||||
{ \
|
||||
List_t * const pxConstList = ( pxList ); \
|
||||
/* Increment the index to the next item and return the item, ensuring */ \
|
||||
/* we don't return the marker used at the end of the list. */ \
|
||||
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
|
||||
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
|
||||
{ \
|
||||
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
|
||||
} \
|
||||
( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Access function to obtain the owner of the first entry in a list. Lists
|
||||
* are normally sorted in ascending item value order.
|
||||
*
|
||||
* This function returns the pxOwner member of the first item in the list.
|
||||
* The pxOwner parameter of a list item is a pointer to the object that owns
|
||||
* the list item. In the scheduler this is normally a task control block.
|
||||
* The pxOwner parameter effectively creates a two way link between the list
|
||||
* item and its owner.
|
||||
*
|
||||
* @param pxList The list from which the owner of the head item is to be
|
||||
* returned.
|
||||
*
|
||||
* \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )
|
||||
|
||||
/*
|
||||
* Check to see if a list item is within a list. The list item maintains a
|
||||
* "container" pointer that points to the list it is in. All this macro does
|
||||
* is check to see if the container and the list match.
|
||||
*
|
||||
* @param pxList The list we want to know if the list item is within.
|
||||
* @param pxListItem The list item we want to know if is in the list.
|
||||
* @return pdTRUE if the list item is in the list, otherwise pdFALSE.
|
||||
*/
|
||||
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( BaseType_t ) ( ( pxListItem )->pvContainer == ( void * ) ( pxList ) ) )
|
||||
|
||||
/*
|
||||
* Return the list a list item is contained within (referenced from).
|
||||
*
|
||||
* @param pxListItem The list item being queried.
|
||||
* @return A pointer to the List_t object that references the pxListItem
|
||||
*/
|
||||
#define listLIST_ITEM_CONTAINER( pxListItem ) ( ( pxListItem )->pvContainer )
|
||||
|
||||
/*
|
||||
* This provides a crude means of knowing if a list has been initialised, as
|
||||
* pxList->xListEnd.xItemValue is set to portMAX_DELAY by the vListInitialise()
|
||||
* function.
|
||||
*/
|
||||
#define listLIST_IS_INITIALISED( pxList ) ( ( pxList )->xListEnd.xItemValue == portMAX_DELAY )
|
||||
|
||||
/*
|
||||
* Must be called before a list is used! This initialises all the members
|
||||
* of the list structure and inserts the xListEnd item into the list as a
|
||||
* marker to the back of the list.
|
||||
*
|
||||
* @param pxList Pointer to the list being initialised.
|
||||
*
|
||||
* \page vListInitialise vListInitialise
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Must be called before a list item is used. This sets the list container to
|
||||
* null so the item does not think that it is already contained in a list.
|
||||
*
|
||||
* @param pxItem Pointer to the list item being initialised.
|
||||
*
|
||||
* \page vListInitialiseItem vListInitialiseItem
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInitialiseItem( ListItem_t * const pxItem ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Insert a list item into a list. The item will be inserted into the list in
|
||||
* a position determined by its item value (descending item value order).
|
||||
*
|
||||
* @param pxList The list into which the item is to be inserted.
|
||||
*
|
||||
* @param pxNewListItem The item that is to be placed in the list.
|
||||
*
|
||||
* \page vListInsert vListInsert
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Insert a list item into a list. The item will be inserted in a position
|
||||
* such that it will be the last item within the list returned by multiple
|
||||
* calls to listGET_OWNER_OF_NEXT_ENTRY.
|
||||
*
|
||||
* The list member pxIndex is used to walk through a list. Calling
|
||||
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list.
|
||||
* Placing an item in a list using vListInsertEnd effectively places the item
|
||||
* in the list position pointed to by pxIndex. This means that every other
|
||||
* item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
|
||||
* the pxIndex parameter again points to the item being inserted.
|
||||
*
|
||||
* @param pxList The list into which the item is to be inserted.
|
||||
*
|
||||
* @param pxNewListItem The list item to be inserted into the list.
|
||||
*
|
||||
* \page vListInsertEnd vListInsertEnd
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Remove an item from a list. The list item has a pointer to the list that
|
||||
* it is in, so only the list item need be passed into the function.
|
||||
*
|
||||
* @param uxListRemove The item to be removed. The item will remove itself from
|
||||
* the list pointed to by it's pxContainer parameter.
|
||||
*
|
||||
* @return The number of items that remain in the list after the list item has
|
||||
* been removed.
|
||||
*
|
||||
* \page uxListRemove uxListRemove
|
||||
* \ingroup LinkedList
|
||||
*/
|
||||
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,793 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Message buffers build functionality on top of FreeRTOS stream buffers.
|
||||
* Whereas stream buffers are used to send a continuous stream of data from one
|
||||
* task or interrupt to another, message buffers are used to send variable
|
||||
* length discrete messages from one task or interrupt to another. Their
|
||||
* implementation is light weight, making them particularly suited for interrupt
|
||||
* to task and core to core communication scenarios.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||
* timeout to 0.
|
||||
*
|
||||
* Message buffers hold variable length messages. To enable that, when a
|
||||
* message is written to the message buffer an additional sizeof( size_t ) bytes
|
||||
* are also written to store the message's length (that happens internally, with
|
||||
* the API function). sizeof( size_t ) is typically 4 bytes on a 32-bit
|
||||
* architecture, so writing a 10 byte message to a message buffer on a 32-bit
|
||||
* architecture will actually reduce the available space in the message buffer
|
||||
* by 14 bytes (10 byte are used by the message, and 4 bytes to hold the length
|
||||
* of the message).
|
||||
*/
|
||||
|
||||
#ifndef FREERTOS_MESSAGE_BUFFER_H
|
||||
#define FREERTOS_MESSAGE_BUFFER_H
|
||||
|
||||
/* Message buffers are built onto of stream buffers. */
|
||||
#include "stream_buffer.h"
|
||||
|
||||
#if defined( __cplusplus )
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type by which message buffers are referenced. For example, a call to
|
||||
* xMessageBufferCreate() returns an MessageBufferHandle_t variable that can
|
||||
* then be used as a parameter to xMessageBufferSend(), xMessageBufferReceive(),
|
||||
* etc.
|
||||
*/
|
||||
typedef void * MessageBufferHandle_t;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
MessageBufferHandle_t xMessageBufferCreate( size_t xBufferSizeBytes );
|
||||
</pre>
|
||||
*
|
||||
* Creates a new message buffer using dynamically allocated memory. See
|
||||
* xMessageBufferCreateStatic() for a version that uses statically allocated
|
||||
* memory (memory that is allocated at compile time).
|
||||
*
|
||||
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
|
||||
* FreeRTOSConfig.h for xMessageBufferCreate() to be available.
|
||||
*
|
||||
* @param xBufferSizeBytes The total number of bytes (not messages) the message
|
||||
* buffer will be able to hold at any one time. When a message is written to
|
||||
* the message buffer an additional sizeof( size_t ) bytes are also written to
|
||||
* store the message's length. sizeof( size_t ) is typically 4 bytes on a
|
||||
* 32-bit architecture, so on most 32-bit architectures a 10 byte message will
|
||||
* take up 14 bytes of message buffer space.
|
||||
*
|
||||
* @return If NULL is returned, then the message buffer cannot be created
|
||||
* because there is insufficient heap memory available for FreeRTOS to allocate
|
||||
* the message buffer data structures and storage area. A non-NULL value being
|
||||
* returned indicates that the message buffer has been created successfully -
|
||||
* the returned value should be stored as the handle to the created message
|
||||
* buffer.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
|
||||
void vAFunction( void )
|
||||
{
|
||||
MessageBufferHandle_t xMessageBuffer;
|
||||
const size_t xMessageBufferSizeBytes = 100;
|
||||
|
||||
// Create a message buffer that can hold 100 bytes. The memory used to hold
|
||||
// both the message buffer structure and the messages themselves is allocated
|
||||
// dynamically. Each message added to the buffer consumes an additional 4
|
||||
// bytes which are used to hold the lengh of the message.
|
||||
xMessageBuffer = xMessageBufferCreate( xMessageBufferSizeBytes );
|
||||
|
||||
if( xMessageBuffer == NULL )
|
||||
{
|
||||
// There was not enough heap memory space available to create the
|
||||
// message buffer.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The message buffer was created successfully and can now be used.
|
||||
}
|
||||
|
||||
</pre>
|
||||
* \defgroup xMessageBufferCreate xMessageBufferCreate
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferCreate( xBufferSizeBytes ) ( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
MessageBufferHandle_t xMessageBufferCreateStatic( size_t xBufferSizeBytes,
|
||||
uint8_t *pucMessageBufferStorageArea,
|
||||
StaticMessageBuffer_t *pxStaticMessageBuffer );
|
||||
</pre>
|
||||
* Creates a new message buffer using statically allocated memory. See
|
||||
* xMessageBufferCreate() for a version that uses dynamically allocated memory.
|
||||
*
|
||||
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
|
||||
* pucMessageBufferStorageArea parameter. When a message is written to the
|
||||
* message buffer an additional sizeof( size_t ) bytes are also written to store
|
||||
* the message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
|
||||
* architecture, so on most 32-bit architecture a 10 byte message will take up
|
||||
* 14 bytes of message buffer space. The maximum number of bytes that can be
|
||||
* stored in the message buffer is actually (xBufferSizeBytes - 1).
|
||||
*
|
||||
* @param pucMessageBufferStorageArea Must point to a uint8_t array that is at
|
||||
* least xBufferSizeBytes + 1 big. This is the array to which messages are
|
||||
* copied when they are written to the message buffer.
|
||||
*
|
||||
* @param pxStaticMessageBuffer Must point to a variable of type
|
||||
* StaticMessageBuffer_t, which will be used to hold the message buffer's data
|
||||
* structure.
|
||||
*
|
||||
* @return If the message buffer is created successfully then a handle to the
|
||||
* created message buffer is returned. If either pucMessageBufferStorageArea or
|
||||
* pxStaticmessageBuffer are NULL then NULL is returned.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
|
||||
// Used to dimension the array used to hold the messages. The available space
|
||||
// will actually be one less than this, so 999.
|
||||
#define STORAGE_SIZE_BYTES 1000
|
||||
|
||||
// Defines the memory that will actually hold the messages within the message
|
||||
// buffer.
|
||||
static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
|
||||
|
||||
// The variable used to hold the message buffer structure.
|
||||
StaticMessageBuffer_t xMessageBufferStruct;
|
||||
|
||||
void MyFunction( void )
|
||||
{
|
||||
MessageBufferHandle_t xMessageBuffer;
|
||||
|
||||
xMessageBuffer = xMessageBufferCreateStatic( sizeof( ucBufferStorage ),
|
||||
ucBufferStorage,
|
||||
&xMessageBufferStruct );
|
||||
|
||||
// As neither the pucMessageBufferStorageArea or pxStaticMessageBuffer
|
||||
// parameters were NULL, xMessageBuffer will not be NULL, and can be used to
|
||||
// reference the created message buffer in other message buffer API calls.
|
||||
|
||||
// Other code that uses the message buffer can go here.
|
||||
}
|
||||
|
||||
</pre>
|
||||
* \defgroup xMessageBufferCreateStatic xMessageBufferCreateStatic
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferCreateStatic( xBufferSizeBytes, pucMessageBufferStorageArea, pxStaticMessageBuffer ) ( MessageBufferHandle_t ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, 0, pdTRUE, pucMessageBufferStorageArea, pxStaticMessageBuffer )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xMessageBufferSend( MessageBufferHandle_t xMessageBuffer,
|
||||
const void *pvTxData,
|
||||
size_t xDataLengthBytes,
|
||||
TickType_t xTicksToWait );
|
||||
<pre>
|
||||
*
|
||||
* Sends a discrete message to the message buffer. The message can be any
|
||||
* length that fits within the buffer's free space, and is copied into the
|
||||
* buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xMessageBufferSend() to write to a message buffer from a task. Use
|
||||
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
|
||||
* service routine (ISR).
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer to which a message is
|
||||
* being sent.
|
||||
*
|
||||
* @param pvTxData A pointer to the message that is to be copied into the
|
||||
* message buffer.
|
||||
*
|
||||
* @param xDataLengthBytes The length of the message. That is, the number of
|
||||
* bytes to copy from pvTxData into the message buffer. When a message is
|
||||
* written to the message buffer an additional sizeof( size_t ) bytes are also
|
||||
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
|
||||
* on a 32-bit architecture, so on most 32-bit architecture setting
|
||||
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
|
||||
* bytes (20 bytes of message data and 4 bytes to hold the message length).
|
||||
*
|
||||
* @param xTicksToWait The maximum amount of time the calling task should remain
|
||||
* in the Blocked state to wait for enough space to become available in the
|
||||
* message buffer, should the message buffer have insufficient space when
|
||||
* xMessageBufferSend() is called. The calling task will never block if
|
||||
* xTicksToWait is zero. The block time is specified in tick periods, so the
|
||||
* absolute time it represents is dependent on the tick frequency. The macro
|
||||
* pdMS_TO_TICKS() can be used to convert a time specified in milliseconds into
|
||||
* a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will cause
|
||||
* the task to wait indefinitely (without timing out), provided
|
||||
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
|
||||
* CPU time when they are in the Blocked state.
|
||||
*
|
||||
* @return The number of bytes written to the message buffer. If the call to
|
||||
* xMessageBufferSend() times out before there was enough space to write the
|
||||
* message into the message buffer then zero is returned. If the call did not
|
||||
* time out then xDataLengthBytes is returned.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
void vAFunction( MessageBufferHandle_t xMessageBuffer )
|
||||
{
|
||||
size_t xBytesSent;
|
||||
uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
|
||||
char *pcStringToSend = "String to send";
|
||||
const TickType_t x100ms = pdMS_TO_TICKS( 100 );
|
||||
|
||||
// Send an array to the message buffer, blocking for a maximum of 100ms to
|
||||
// wait for enough space to be available in the message buffer.
|
||||
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
|
||||
|
||||
if( xBytesSent != sizeof( ucArrayToSend ) )
|
||||
{
|
||||
// The call to xMessageBufferSend() times out before there was enough
|
||||
// space in the buffer for the data to be written.
|
||||
}
|
||||
|
||||
// Send the string to the message buffer. Return immediately if there is
|
||||
// not enough space in the buffer.
|
||||
xBytesSent = xMessageBufferSend( xMessageBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
|
||||
|
||||
if( xBytesSent != strlen( pcStringToSend ) )
|
||||
{
|
||||
// The string could not be added to the message buffer because there was
|
||||
// not enough free space in the buffer.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xMessageBufferSend xMessageBufferSend
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xMessageBufferSendFromISR( MessageBufferHandle_t xMessageBuffer,
|
||||
const void *pvTxData,
|
||||
size_t xDataLengthBytes,
|
||||
BaseType_t *pxHigherPriorityTaskWoken );
|
||||
<pre>
|
||||
*
|
||||
* Interrupt safe version of the API function that sends a discrete message to
|
||||
* the message buffer. The message can be any length that fits within the
|
||||
* buffer's free space, and is copied into the buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xMessageBufferSend() to write to a message buffer from a task. Use
|
||||
* xMessageBufferSendFromISR() to write to a message buffer from an interrupt
|
||||
* service routine (ISR).
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer to which a message is
|
||||
* being sent.
|
||||
*
|
||||
* @param pvTxData A pointer to the message that is to be copied into the
|
||||
* message buffer.
|
||||
*
|
||||
* @param xDataLengthBytes The length of the message. That is, the number of
|
||||
* bytes to copy from pvTxData into the message buffer. When a message is
|
||||
* written to the message buffer an additional sizeof( size_t ) bytes are also
|
||||
* written to store the message's length. sizeof( size_t ) is typically 4 bytes
|
||||
* on a 32-bit architecture, so on most 32-bit architecture setting
|
||||
* xDataLengthBytes to 20 will reduce the free space in the message buffer by 24
|
||||
* bytes (20 bytes of message data and 4 bytes to hold the message length).
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
|
||||
* have a task blocked on it waiting for data. Calling
|
||||
* xMessageBufferSendFromISR() can make data available, and so cause a task that
|
||||
* was waiting for data to leave the Blocked state. If calling
|
||||
* xMessageBufferSendFromISR() causes a task to leave the Blocked state, and the
|
||||
* unblocked task has a priority higher than the currently executing task (the
|
||||
* task that was interrupted), then, internally, xMessageBufferSendFromISR()
|
||||
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
|
||||
* xMessageBufferSendFromISR() sets this value to pdTRUE, then normally a
|
||||
* context switch should be performed before the interrupt is exited. This will
|
||||
* ensure that the interrupt returns directly to the highest priority Ready
|
||||
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
|
||||
* is passed into the function. See the code example below for an example.
|
||||
*
|
||||
* @return The number of bytes actually written to the message buffer. If the
|
||||
* message buffer didn't have enough free space for the message to be stored
|
||||
* then 0 is returned, otherwise xDataLengthBytes is returned.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
// A message buffer that has already been created.
|
||||
MessageBufferHandle_t xMessageBuffer;
|
||||
|
||||
void vAnInterruptServiceRoutine( void )
|
||||
{
|
||||
size_t xBytesSent;
|
||||
char *pcStringToSend = "String to send";
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||
|
||||
// Attempt to send the string to the message buffer.
|
||||
xBytesSent = xMessageBufferSendFromISR( xMessageBuffer,
|
||||
( void * ) pcStringToSend,
|
||||
strlen( pcStringToSend ),
|
||||
&xHigherPriorityTaskWoken );
|
||||
|
||||
if( xBytesSent != strlen( pcStringToSend ) )
|
||||
{
|
||||
// The string could not be added to the message buffer because there was
|
||||
// not enough free space in the buffer.
|
||||
}
|
||||
|
||||
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||
// xMessageBufferSendFromISR() then a task that has a priority above the
|
||||
// priority of the currently executing task was unblocked and a context
|
||||
// switch should be performed to ensure the ISR returns to the unblocked
|
||||
// task. In most FreeRTOS ports this is done by simply passing
|
||||
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
|
||||
// variables value, and perform the context switch if necessary. Check the
|
||||
// documentation for the port in use for port specific instructions.
|
||||
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xMessageBufferReceive( MessageBufferHandle_t xMessageBuffer,
|
||||
void *pvRxData,
|
||||
size_t xBufferLengthBytes,
|
||||
TickType_t xTicksToWait );
|
||||
</pre>
|
||||
*
|
||||
* Receives a discrete message from a message buffer. Messages can be of
|
||||
* variable length and are copied out of the buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
|
||||
* xMessageBufferReceiveFromISR() to read from a message buffer from an
|
||||
* interrupt service routine (ISR).
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer from which a message
|
||||
* is being received.
|
||||
*
|
||||
* @param pvRxData A pointer to the buffer into which the received message is
|
||||
* to be copied.
|
||||
*
|
||||
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
|
||||
* parameter. This sets the maximum length of the message that can be received.
|
||||
* If xBufferLengthBytes is too small to hold the next message then the message
|
||||
* will be left in the message buffer and 0 will be returned.
|
||||
*
|
||||
* @param xTicksToWait The maximum amount of time the task should remain in the
|
||||
* Blocked state to wait for a message, should the message buffer be empty.
|
||||
* xMessageBufferReceive() will return immediately if xTicksToWait is zero and
|
||||
* the message buffer is empty. The block time is specified in tick periods, so
|
||||
* the absolute time it represents is dependent on the tick frequency. The
|
||||
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
|
||||
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
|
||||
* cause the task to wait indefinitely (without timing out), provided
|
||||
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. Tasks do not use any
|
||||
* CPU time when they are in the Blocked state.
|
||||
*
|
||||
* @return The length, in bytes, of the message read from the message buffer, if
|
||||
* any. If xMessageBufferReceive() times out before a message became available
|
||||
* then zero is returned. If the length of the message is greater than
|
||||
* xBufferLengthBytes then the message will be left in the message buffer and
|
||||
* zero is returned.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
void vAFunction( MessageBuffer_t xMessageBuffer )
|
||||
{
|
||||
uint8_t ucRxData[ 20 ];
|
||||
size_t xReceivedBytes;
|
||||
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
|
||||
|
||||
// Receive the next message from the message buffer. Wait in the Blocked
|
||||
// state (so not using any CPU processing time) for a maximum of 100ms for
|
||||
// a message to become available.
|
||||
xReceivedBytes = xMessageBufferReceive( xMessageBuffer,
|
||||
( void * ) ucRxData,
|
||||
sizeof( ucRxData ),
|
||||
xBlockTime );
|
||||
|
||||
if( xReceivedBytes > 0 )
|
||||
{
|
||||
// A ucRxData contains a message that is xReceivedBytes long. Process
|
||||
// the message here....
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xMessageBufferReceive xMessageBufferReceive
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait )
|
||||
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xMessageBufferReceiveFromISR( MessageBufferHandle_t xMessageBuffer,
|
||||
void *pvRxData,
|
||||
size_t xBufferLengthBytes,
|
||||
BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* An interrupt safe version of the API function that receives a discrete
|
||||
* message from a message buffer. Messages can be of variable length and are
|
||||
* copied out of the buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xMessageBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xMessageBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xMessageBufferReceive() to read from a message buffer from a task. Use
|
||||
* xMessageBufferReceiveFromISR() to read from a message buffer from an
|
||||
* interrupt service routine (ISR).
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer from which a message
|
||||
* is being received.
|
||||
*
|
||||
* @param pvRxData A pointer to the buffer into which the received message is
|
||||
* to be copied.
|
||||
*
|
||||
* @param xBufferLengthBytes The length of the buffer pointed to by the pvRxData
|
||||
* parameter. This sets the maximum length of the message that can be received.
|
||||
* If xBufferLengthBytes is too small to hold the next message then the message
|
||||
* will be left in the message buffer and 0 will be returned.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken It is possible that a message buffer will
|
||||
* have a task blocked on it waiting for space to become available. Calling
|
||||
* xMessageBufferReceiveFromISR() can make space available, and so cause a task
|
||||
* that is waiting for space to leave the Blocked state. If calling
|
||||
* xMessageBufferReceiveFromISR() causes a task to leave the Blocked state, and
|
||||
* the unblocked task has a priority higher than the currently executing task
|
||||
* (the task that was interrupted), then, internally,
|
||||
* xMessageBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
|
||||
* If xMessageBufferReceiveFromISR() sets this value to pdTRUE, then normally a
|
||||
* context switch should be performed before the interrupt is exited. That will
|
||||
* ensure the interrupt returns directly to the highest priority Ready state
|
||||
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
|
||||
* passed into the function. See the code example below for an example.
|
||||
*
|
||||
* @return The length, in bytes, of the message read from the message buffer, if
|
||||
* any.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
// A message buffer that has already been created.
|
||||
MessageBuffer_t xMessageBuffer;
|
||||
|
||||
void vAnInterruptServiceRoutine( void )
|
||||
{
|
||||
uint8_t ucRxData[ 20 ];
|
||||
size_t xReceivedBytes;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||
|
||||
// Receive the next message from the message buffer.
|
||||
xReceivedBytes = xMessageBufferReceiveFromISR( xMessageBuffer,
|
||||
( void * ) ucRxData,
|
||||
sizeof( ucRxData ),
|
||||
&xHigherPriorityTaskWoken );
|
||||
|
||||
if( xReceivedBytes > 0 )
|
||||
{
|
||||
// A ucRxData contains a message that is xReceivedBytes long. Process
|
||||
// the message here....
|
||||
}
|
||||
|
||||
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||
// xMessageBufferReceiveFromISR() then a task that has a priority above the
|
||||
// priority of the currently executing task was unblocked and a context
|
||||
// switch should be performed to ensure the ISR returns to the unblocked
|
||||
// task. In most FreeRTOS ports this is done by simply passing
|
||||
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
|
||||
// variables value, and perform the context switch if necessary. Check the
|
||||
// documentation for the port in use for port specific instructions.
|
||||
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
void vMessageBufferDelete( MessageBufferHandle_t xMessageBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Deletes a message buffer that was previously created using a call to
|
||||
* xMessageBufferCreate() or xMessageBufferCreateStatic(). If the message
|
||||
* buffer was created using dynamic memory (that is, by xMessageBufferCreate()),
|
||||
* then the allocated memory is freed.
|
||||
*
|
||||
* A message buffer handle must not be used after the message buffer has been
|
||||
* deleted.
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer to be deleted.
|
||||
*
|
||||
*/
|
||||
#define vMessageBufferDelete( xMessageBuffer ) vStreamBufferDelete( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
<pre>
|
||||
BaseType_t xMessageBufferIsFull( MessageBufferHandle_t xMessageBuffer ) );
|
||||
</pre>
|
||||
*
|
||||
* Tests to see if a message buffer is full. A message buffer is full if it
|
||||
* cannot accept any more messages, of any size, until space is made available
|
||||
* by a message being removed from the message buffer.
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||
*
|
||||
* @return If the message buffer referenced by xMessageBuffer is full then
|
||||
* pdTRUE is returned. Otherwise pdFALSE is returned.
|
||||
*/
|
||||
#define xMessageBufferIsFull( xMessageBuffer ) xStreamBufferIsFull( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
<pre>
|
||||
BaseType_t xMessageBufferIsEmpty( MessageBufferHandle_t xMessageBuffer ) );
|
||||
</pre>
|
||||
*
|
||||
* Tests to see if a message buffer is empty (does not contain any messages).
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||
*
|
||||
* @return If the message buffer referenced by xMessageBuffer is empty then
|
||||
* pdTRUE is returned. Otherwise pdFALSE is returned.
|
||||
*
|
||||
*/
|
||||
#define xMessageBufferIsEmpty( xMessageBuffer ) xStreamBufferIsEmpty( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
<pre>
|
||||
BaseType_t xMessageBufferReset( MessageBufferHandle_t xMessageBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Resets a message buffer to its initial empty state, discarding any message it
|
||||
* contained.
|
||||
*
|
||||
* A message buffer can only be reset if there are no tasks blocked on it.
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer being reset.
|
||||
*
|
||||
* @return If the message buffer was reset then pdPASS is returned. If the
|
||||
* message buffer could not be reset because either there was a task blocked on
|
||||
* the message queue to wait for space to become available, or to wait for a
|
||||
* a message to be available, then pdFAIL is returned.
|
||||
*
|
||||
* \defgroup xMessageBufferReset xMessageBufferReset
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferReset( xMessageBuffer ) xStreamBufferReset( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
<pre>
|
||||
size_t xMessageBufferSpaceAvailable( MessageBufferHandle_t xMessageBuffer ) );
|
||||
</pre>
|
||||
* Returns the number of bytes of free space in the message buffer.
|
||||
*
|
||||
* @param xMessageBuffer The handle of the message buffer being queried.
|
||||
*
|
||||
* @return The number of bytes that can be written to the message buffer before
|
||||
* the message buffer would be full. When a message is written to the message
|
||||
* buffer an additional sizeof( size_t ) bytes are also written to store the
|
||||
* message's length. sizeof( size_t ) is typically 4 bytes on a 32-bit
|
||||
* architecture, so if xMessageBufferSpacesAvailable() returns 10, then the size
|
||||
* of the largest message that can be written to the message buffer is 6 bytes.
|
||||
*
|
||||
* \defgroup xMessageBufferSpaceAvailable xMessageBufferSpaceAvailable
|
||||
* \ingroup MessageBufferManagement
|
||||
*/
|
||||
#define xMessageBufferSpaceAvailable( xMessageBuffer ) xStreamBufferSpacesAvailable( ( StreamBufferHandle_t ) xMessageBuffer )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xMessageBufferSendCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* For advanced users only.
|
||||
*
|
||||
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||
* data is sent to a message buffer or stream buffer. If there was a task that
|
||||
* was blocked on the message or stream buffer waiting for data to arrive then
|
||||
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
|
||||
* from the Blocked state. xMessageBufferSendCompletedFromISR() does the same
|
||||
* thing. It is provided to enable application writers to implement their own
|
||||
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
|
||||
*
|
||||
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||
* additional information.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer to which data was
|
||||
* written.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||
* initialised to pdFALSE before it is passed into
|
||||
* xMessageBufferSendCompletedFromISR(). If calling
|
||||
* xMessageBufferSendCompletedFromISR() removes a task from the Blocked state,
|
||||
* and the task has a priority above the priority of the currently running task,
|
||||
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||
* context switch should be performed before exiting the ISR.
|
||||
*
|
||||
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||
* Otherwise pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xMessageBufferSendCompletedFromISR xMessageBufferSendCompletedFromISR
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
#define xMessageBufferSendCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferSendCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xMessageBufferReceiveCompletedFromISR( MessageBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* For advanced users only.
|
||||
*
|
||||
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||
* data is read out of a message buffer or stream buffer. If there was a task
|
||||
* that was blocked on the message or stream buffer waiting for data to arrive
|
||||
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
|
||||
* remove it from the Blocked state. xMessageBufferReceiveCompletedFromISR()
|
||||
* does the same thing. It is provided to enable application writers to
|
||||
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
|
||||
* ANY OTHER TIME.
|
||||
*
|
||||
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||
* additional information.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer from which data was
|
||||
* read.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||
* initialised to pdFALSE before it is passed into
|
||||
* xMessageBufferReceiveCompletedFromISR(). If calling
|
||||
* xMessageBufferReceiveCompletedFromISR() removes a task from the Blocked state,
|
||||
* and the task has a priority above the priority of the currently running task,
|
||||
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||
* context switch should be performed before exiting the ISR.
|
||||
*
|
||||
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||
* Otherwise pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xMessageBufferReceiveCompletedFromISR xMessageBufferReceiveCompletedFromISR
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
#define xMessageBufferReceiveCompletedFromISR( xMessageBuffer, pxHigherPriorityTaskWoken ) xStreamBufferReceiveCompletedFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pxHigherPriorityTaskWoken )
|
||||
|
||||
#if defined( __cplusplus )
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !defined( FREERTOS_MESSAGE_BUFFER_H ) */
|
|
@ -0,0 +1,169 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* When the MPU is used the standard (non MPU) API functions are mapped to
|
||||
* equivalents that start "MPU_", the prototypes for which are defined in this
|
||||
* header files. This will cause the application code to call the MPU_ version
|
||||
* which wraps the non-MPU version with privilege promoting then demoting code,
|
||||
* so the kernel code always runs will full privileges.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MPU_PROTOTYPES_H
|
||||
#define MPU_PROTOTYPES_H
|
||||
|
||||
/* MPU versions of tasks.h API functions. */
|
||||
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask );
|
||||
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer );
|
||||
BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
|
||||
BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
|
||||
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
|
||||
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
|
||||
void MPU_vTaskDelay( const TickType_t xTicksToDelay );
|
||||
void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement );
|
||||
BaseType_t MPU_xTaskAbortDelay( TaskHandle_t xTask );
|
||||
UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t xTask );
|
||||
eTaskState MPU_eTaskGetState( TaskHandle_t xTask );
|
||||
void MPU_vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState );
|
||||
void MPU_vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority );
|
||||
void MPU_vTaskSuspend( TaskHandle_t xTaskToSuspend );
|
||||
void MPU_vTaskResume( TaskHandle_t xTaskToResume );
|
||||
void MPU_vTaskStartScheduler( void );
|
||||
void MPU_vTaskSuspendAll( void );
|
||||
BaseType_t MPU_xTaskResumeAll( void );
|
||||
TickType_t MPU_xTaskGetTickCount( void );
|
||||
UBaseType_t MPU_uxTaskGetNumberOfTasks( void );
|
||||
char * MPU_pcTaskGetName( TaskHandle_t xTaskToQuery );
|
||||
TaskHandle_t MPU_xTaskGetHandle( const char *pcNameToQuery );
|
||||
UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
|
||||
void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxHookFunction );
|
||||
TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask );
|
||||
void MPU_vTaskSetThreadLocalStoragePointer( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue );
|
||||
void * MPU_pvTaskGetThreadLocalStoragePointer( TaskHandle_t xTaskToQuery, BaseType_t xIndex );
|
||||
BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter );
|
||||
TaskHandle_t MPU_xTaskGetIdleTaskHandle( void );
|
||||
UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime );
|
||||
void MPU_vTaskList( char * pcWriteBuffer );
|
||||
void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer );
|
||||
BaseType_t MPU_xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue );
|
||||
BaseType_t MPU_xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
|
||||
uint32_t MPU_ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
|
||||
BaseType_t MPU_xTaskNotifyStateClear( TaskHandle_t xTask );
|
||||
BaseType_t MPU_xTaskIncrementTick( void );
|
||||
TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void );
|
||||
void MPU_vTaskSetTimeOutState( TimeOut_t * const pxTimeOut );
|
||||
BaseType_t MPU_xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait );
|
||||
void MPU_vTaskMissedYield( void );
|
||||
BaseType_t MPU_xTaskGetSchedulerState( void );
|
||||
|
||||
/* MPU versions of queue.h API functions. */
|
||||
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition );
|
||||
BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
|
||||
BaseType_t MPU_xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
|
||||
BaseType_t MPU_xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait );
|
||||
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue );
|
||||
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
|
||||
void MPU_vQueueDelete( QueueHandle_t xQueue );
|
||||
QueueHandle_t MPU_xQueueCreateMutex( const uint8_t ucQueueType );
|
||||
QueueHandle_t MPU_xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue );
|
||||
QueueHandle_t MPU_xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount );
|
||||
QueueHandle_t MPU_xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue );
|
||||
void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore );
|
||||
BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait );
|
||||
BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t pxMutex );
|
||||
void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcName );
|
||||
void MPU_vQueueUnregisterQueue( QueueHandle_t xQueue );
|
||||
const char * MPU_pcQueueGetName( QueueHandle_t xQueue );
|
||||
QueueHandle_t MPU_xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType );
|
||||
QueueHandle_t MPU_xQueueGenericCreateStatic( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, uint8_t *pucQueueStorage, StaticQueue_t *pxStaticQueue, const uint8_t ucQueueType );
|
||||
QueueSetHandle_t MPU_xQueueCreateSet( const UBaseType_t uxEventQueueLength );
|
||||
BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet );
|
||||
BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet );
|
||||
QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, const TickType_t xTicksToWait );
|
||||
BaseType_t MPU_xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue );
|
||||
void MPU_vQueueSetQueueNumber( QueueHandle_t xQueue, UBaseType_t uxQueueNumber );
|
||||
UBaseType_t MPU_uxQueueGetQueueNumber( QueueHandle_t xQueue );
|
||||
uint8_t MPU_ucQueueGetQueueType( QueueHandle_t xQueue );
|
||||
|
||||
/* MPU versions of timers.h API functions. */
|
||||
TimerHandle_t MPU_xTimerCreate( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction );
|
||||
TimerHandle_t MPU_xTimerCreateStatic( const char * const pcTimerName, const TickType_t xTimerPeriodInTicks, const UBaseType_t uxAutoReload, void * const pvTimerID, TimerCallbackFunction_t pxCallbackFunction, StaticTimer_t *pxTimerBuffer );
|
||||
void * MPU_pvTimerGetTimerID( const TimerHandle_t xTimer );
|
||||
void MPU_vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );
|
||||
BaseType_t MPU_xTimerIsTimerActive( TimerHandle_t xTimer );
|
||||
TaskHandle_t MPU_xTimerGetTimerDaemonTaskHandle( void );
|
||||
BaseType_t MPU_xTimerPendFunctionCall( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, TickType_t xTicksToWait );
|
||||
const char * MPU_pcTimerGetName( TimerHandle_t xTimer );
|
||||
TickType_t MPU_xTimerGetPeriod( TimerHandle_t xTimer );
|
||||
TickType_t MPU_xTimerGetExpiryTime( TimerHandle_t xTimer );
|
||||
BaseType_t MPU_xTimerCreateTimerTask( void );
|
||||
BaseType_t MPU_xTimerGenericCommand( TimerHandle_t xTimer, const BaseType_t xCommandID, const TickType_t xOptionalValue, BaseType_t * const pxHigherPriorityTaskWoken, const TickType_t xTicksToWait );
|
||||
|
||||
/* MPU versions of event_group.h API functions. */
|
||||
EventGroupHandle_t MPU_xEventGroupCreate( void );
|
||||
EventGroupHandle_t MPU_xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );
|
||||
EventBits_t MPU_xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait );
|
||||
EventBits_t MPU_xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
|
||||
EventBits_t MPU_xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );
|
||||
EventBits_t MPU_xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait );
|
||||
void MPU_vEventGroupDelete( EventGroupHandle_t xEventGroup );
|
||||
UBaseType_t MPU_uxEventGroupGetNumber( void* xEventGroup );
|
||||
|
||||
/* MPU versions of message/stream_buffer.h API functions. */
|
||||
size_t MPU_xStreamBufferSend( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, TickType_t xTicksToWait );
|
||||
size_t MPU_xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer, const void *pvTxData, size_t xDataLengthBytes, BaseType_t * const pxHigherPriorityTaskWoken );
|
||||
size_t MPU_xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, TickType_t xTicksToWait );
|
||||
size_t MPU_xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer, void *pvRxData, size_t xBufferLengthBytes, BaseType_t * const pxHigherPriorityTaskWoken );
|
||||
void MPU_vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );
|
||||
BaseType_t MPU_xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );
|
||||
BaseType_t MPU_xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
|
||||
BaseType_t MPU_xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );
|
||||
size_t MPU_xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
|
||||
size_t MPU_xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
|
||||
BaseType_t MPU_xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
|
||||
StreamBufferHandle_t MPU_xStreamBufferGenericCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer );
|
||||
StreamBufferHandle_t MPU_xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes, size_t xTriggerLevelBytes, BaseType_t xIsMessageBuffer, uint8_t * const pucStreamBufferStorageArea, StaticStreamBuffer_t * const pxStaticStreamBuffer );
|
||||
|
||||
|
||||
|
||||
#endif /* MPU_PROTOTYPES_H */
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef MPU_WRAPPERS_H
|
||||
#define MPU_WRAPPERS_H
|
||||
|
||||
/* This file redefines API functions to be called through a wrapper macro, but
|
||||
only for ports that are using the MPU. */
|
||||
#ifdef portUSING_MPU_WRAPPERS
|
||||
|
||||
/* MPU_WRAPPERS_INCLUDED_FROM_API_FILE will be defined when this file is
|
||||
included from queue.c or task.c to prevent it from having an effect within
|
||||
those files. */
|
||||
#ifndef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
/*
|
||||
* Map standard (non MPU) API functions to equivalents that start
|
||||
* "MPU_". This will cause the application code to call the MPU_
|
||||
* version, which wraps the non-MPU version with privilege promoting
|
||||
* then demoting code, so the kernel code always runs will full
|
||||
* privileges.
|
||||
*/
|
||||
|
||||
/* Map standard tasks.h API functions to the MPU equivalents. */
|
||||
#define xTaskCreate MPU_xTaskCreate
|
||||
#define xTaskCreateStatic MPU_xTaskCreateStatic
|
||||
#define xTaskCreateRestricted MPU_xTaskCreateRestricted
|
||||
#define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions
|
||||
#define vTaskDelete MPU_vTaskDelete
|
||||
#define vTaskDelay MPU_vTaskDelay
|
||||
#define vTaskDelayUntil MPU_vTaskDelayUntil
|
||||
#define xTaskAbortDelay MPU_xTaskAbortDelay
|
||||
#define uxTaskPriorityGet MPU_uxTaskPriorityGet
|
||||
#define eTaskGetState MPU_eTaskGetState
|
||||
#define vTaskGetInfo MPU_vTaskGetInfo
|
||||
#define vTaskPrioritySet MPU_vTaskPrioritySet
|
||||
#define vTaskSuspend MPU_vTaskSuspend
|
||||
#define vTaskResume MPU_vTaskResume
|
||||
#define vTaskSuspendAll MPU_vTaskSuspendAll
|
||||
#define xTaskResumeAll MPU_xTaskResumeAll
|
||||
#define xTaskGetTickCount MPU_xTaskGetTickCount
|
||||
#define uxTaskGetNumberOfTasks MPU_uxTaskGetNumberOfTasks
|
||||
#define pcTaskGetName MPU_pcTaskGetName
|
||||
#define xTaskGetHandle MPU_xTaskGetHandle
|
||||
#define uxTaskGetStackHighWaterMark MPU_uxTaskGetStackHighWaterMark
|
||||
#define vTaskSetApplicationTaskTag MPU_vTaskSetApplicationTaskTag
|
||||
#define xTaskGetApplicationTaskTag MPU_xTaskGetApplicationTaskTag
|
||||
#define vTaskSetThreadLocalStoragePointer MPU_vTaskSetThreadLocalStoragePointer
|
||||
#define pvTaskGetThreadLocalStoragePointer MPU_pvTaskGetThreadLocalStoragePointer
|
||||
#define xTaskCallApplicationTaskHook MPU_xTaskCallApplicationTaskHook
|
||||
#define xTaskGetIdleTaskHandle MPU_xTaskGetIdleTaskHandle
|
||||
#define uxTaskGetSystemState MPU_uxTaskGetSystemState
|
||||
#define vTaskList MPU_vTaskList
|
||||
#define vTaskGetRunTimeStats MPU_vTaskGetRunTimeStats
|
||||
#define xTaskGenericNotify MPU_xTaskGenericNotify
|
||||
#define xTaskNotifyWait MPU_xTaskNotifyWait
|
||||
#define ulTaskNotifyTake MPU_ulTaskNotifyTake
|
||||
#define xTaskNotifyStateClear MPU_xTaskNotifyStateClear
|
||||
|
||||
#define xTaskGetCurrentTaskHandle MPU_xTaskGetCurrentTaskHandle
|
||||
#define vTaskSetTimeOutState MPU_vTaskSetTimeOutState
|
||||
#define xTaskCheckForTimeOut MPU_xTaskCheckForTimeOut
|
||||
#define xTaskGetSchedulerState MPU_xTaskGetSchedulerState
|
||||
|
||||
/* Map standard queue.h API functions to the MPU equivalents. */
|
||||
#define xQueueGenericSend MPU_xQueueGenericSend
|
||||
#define xQueueReceive MPU_xQueueReceive
|
||||
#define xQueuePeek MPU_xQueuePeek
|
||||
#define xQueueSemaphoreTake MPU_xQueueSemaphoreTake
|
||||
#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
|
||||
#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
|
||||
#define vQueueDelete MPU_vQueueDelete
|
||||
#define xQueueCreateMutex MPU_xQueueCreateMutex
|
||||
#define xQueueCreateMutexStatic MPU_xQueueCreateMutexStatic
|
||||
#define xQueueCreateCountingSemaphore MPU_xQueueCreateCountingSemaphore
|
||||
#define xQueueCreateCountingSemaphoreStatic MPU_xQueueCreateCountingSemaphoreStatic
|
||||
#define xQueueGetMutexHolder MPU_xQueueGetMutexHolder
|
||||
#define xQueueTakeMutexRecursive MPU_xQueueTakeMutexRecursive
|
||||
#define xQueueGiveMutexRecursive MPU_xQueueGiveMutexRecursive
|
||||
#define xQueueGenericCreate MPU_xQueueGenericCreate
|
||||
#define xQueueGenericCreateStatic MPU_xQueueGenericCreateStatic
|
||||
#define xQueueCreateSet MPU_xQueueCreateSet
|
||||
#define xQueueAddToSet MPU_xQueueAddToSet
|
||||
#define xQueueRemoveFromSet MPU_xQueueRemoveFromSet
|
||||
#define xQueueSelectFromSet MPU_xQueueSelectFromSet
|
||||
#define xQueueGenericReset MPU_xQueueGenericReset
|
||||
|
||||
#if( configQUEUE_REGISTRY_SIZE > 0 )
|
||||
#define vQueueAddToRegistry MPU_vQueueAddToRegistry
|
||||
#define vQueueUnregisterQueue MPU_vQueueUnregisterQueue
|
||||
#define pcQueueGetName MPU_pcQueueGetName
|
||||
#endif
|
||||
|
||||
/* Map standard timer.h API functions to the MPU equivalents. */
|
||||
#define xTimerCreate MPU_xTimerCreate
|
||||
#define xTimerCreateStatic MPU_xTimerCreateStatic
|
||||
#define pvTimerGetTimerID MPU_pvTimerGetTimerID
|
||||
#define vTimerSetTimerID MPU_vTimerSetTimerID
|
||||
#define xTimerIsTimerActive MPU_xTimerIsTimerActive
|
||||
#define xTimerGetTimerDaemonTaskHandle MPU_xTimerGetTimerDaemonTaskHandle
|
||||
#define xTimerPendFunctionCall MPU_xTimerPendFunctionCall
|
||||
#define pcTimerGetName MPU_pcTimerGetName
|
||||
#define xTimerGetPeriod MPU_xTimerGetPeriod
|
||||
#define xTimerGetExpiryTime MPU_xTimerGetExpiryTime
|
||||
#define xTimerGenericCommand MPU_xTimerGenericCommand
|
||||
|
||||
/* Map standard event_group.h API functions to the MPU equivalents. */
|
||||
#define xEventGroupCreate MPU_xEventGroupCreate
|
||||
#define xEventGroupCreateStatic MPU_xEventGroupCreateStatic
|
||||
#define xEventGroupWaitBits MPU_xEventGroupWaitBits
|
||||
#define xEventGroupClearBits MPU_xEventGroupClearBits
|
||||
#define xEventGroupSetBits MPU_xEventGroupSetBits
|
||||
#define xEventGroupSync MPU_xEventGroupSync
|
||||
#define vEventGroupDelete MPU_vEventGroupDelete
|
||||
|
||||
/* Map standard message/stream_buffer.h API functions to the MPU
|
||||
equivalents. */
|
||||
#define xStreamBufferSend MPU_xStreamBufferSend
|
||||
#define xStreamBufferSendFromISR MPU_xStreamBufferSendFromISR
|
||||
#define xStreamBufferReceive MPU_xStreamBufferReceive
|
||||
#define xStreamBufferReceiveFromISR MPU_xStreamBufferReceiveFromISR
|
||||
#define vStreamBufferDelete MPU_vStreamBufferDelete
|
||||
#define xStreamBufferIsFull MPU_xStreamBufferIsFull
|
||||
#define xStreamBufferIsEmpty MPU_xStreamBufferIsEmpty
|
||||
#define xStreamBufferReset MPU_xStreamBufferReset
|
||||
#define xStreamBufferSpacesAvailable MPU_xStreamBufferSpacesAvailable
|
||||
#define xStreamBufferBytesAvailable MPU_xStreamBufferBytesAvailable
|
||||
#define xStreamBufferSetTriggerLevel MPU_xStreamBufferSetTriggerLevel
|
||||
#define xStreamBufferGenericCreate MPU_xStreamBufferGenericCreate
|
||||
#define xStreamBufferGenericCreateStatic MPU_xStreamBufferGenericCreateStatic
|
||||
|
||||
|
||||
/* Remove the privileged function macro, but keep the PRIVILEGED_DATA
|
||||
macro so applications can place data in privileged access sections
|
||||
(useful when using statically allocated objects). */
|
||||
#define PRIVILEGED_FUNCTION
|
||||
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
|
||||
|
||||
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
|
||||
|
||||
/* Ensure API functions go in the privileged execution section. */
|
||||
#define PRIVILEGED_FUNCTION __attribute__((section("privileged_functions")))
|
||||
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
|
||||
|
||||
#endif /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
|
||||
|
||||
#else /* portUSING_MPU_WRAPPERS */
|
||||
|
||||
#define PRIVILEGED_FUNCTION
|
||||
#define PRIVILEGED_DATA
|
||||
#define portUSING_MPU_WRAPPERS 0
|
||||
|
||||
#endif /* portUSING_MPU_WRAPPERS */
|
||||
|
||||
|
||||
#endif /* MPU_WRAPPERS_H */
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Portable layer API. Each function must be defined for each port.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#ifndef PORTABLE_H
|
||||
#define PORTABLE_H
|
||||
|
||||
/* Each FreeRTOS port has a unique portmacro.h header file. Originally a
|
||||
pre-processor definition was used to ensure the pre-processor found the correct
|
||||
portmacro.h file for the port being used. That scheme was deprecated in favour
|
||||
of setting the compiler's include path such that it found the correct
|
||||
portmacro.h file - removing the need for the constant and allowing the
|
||||
portmacro.h file to be located anywhere in relation to the port being used.
|
||||
Purely for reasons of backward compatibility the old method is still valid, but
|
||||
to make it clear that new projects should not use it, support for the port
|
||||
specific constants has been moved into the deprecated_definitions.h header
|
||||
file. */
|
||||
|
||||
/* If portENTER_CRITICAL is not defined then including deprecated_definitions.h
|
||||
did not result in a portmacro.h header file being included - and it should be
|
||||
included here. In this case the path to the correct portmacro.h header file
|
||||
must be set in the compiler's include path. */
|
||||
#ifndef portENTER_CRITICAL
|
||||
#include "portmacro.h"
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 32
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x001f )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 16
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x000f )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 8
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 4
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 2
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0001 )
|
||||
#endif
|
||||
|
||||
#if portBYTE_ALIGNMENT == 1
|
||||
#define portBYTE_ALIGNMENT_MASK ( 0x0000 )
|
||||
#endif
|
||||
|
||||
#ifndef portBYTE_ALIGNMENT_MASK
|
||||
#error "Invalid portBYTE_ALIGNMENT definition"
|
||||
#endif
|
||||
|
||||
#ifndef portNUM_CONFIGURABLE_REGIONS
|
||||
#define portNUM_CONFIGURABLE_REGIONS 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mpu_wrappers.h"
|
||||
|
||||
/*
|
||||
* Setup the stack of a new task so it is ready to be placed under the
|
||||
* scheduler control. The registers have to be placed on the stack in
|
||||
* the order that the port expects to find them.
|
||||
*
|
||||
*/
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) PRIVILEGED_FUNCTION;
|
||||
#else
|
||||
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/* Used by heap_5.c. */
|
||||
typedef struct HeapRegion
|
||||
{
|
||||
uint8_t *pucStartAddress;
|
||||
size_t xSizeInBytes;
|
||||
} HeapRegion_t;
|
||||
|
||||
/*
|
||||
* Used to define multiple heap regions for use by heap_5.c. This function
|
||||
* must be called before any calls to pvPortMalloc() - not creating a task,
|
||||
* queue, semaphore, mutex, software timer, event group, etc. will result in
|
||||
* pvPortMalloc being called.
|
||||
*
|
||||
* pxHeapRegions passes in an array of HeapRegion_t structures - each of which
|
||||
* defines a region of memory that can be used as the heap. The array is
|
||||
* terminated by a HeapRegions_t structure that has a size of 0. The region
|
||||
* with the lowest start address must appear first in the array.
|
||||
*/
|
||||
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
||||
/*
|
||||
* Map to the memory management routines required for the port.
|
||||
*/
|
||||
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
|
||||
void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
|
||||
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
|
||||
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||
size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Setup the hardware ready for the scheduler to take control. This generally
|
||||
* sets up a tick interrupt and sets timers for the correct tick frequency.
|
||||
*/
|
||||
BaseType_t xPortStartScheduler( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
|
||||
* the hardware is left in its original condition after the scheduler stops
|
||||
* executing.
|
||||
*/
|
||||
void vPortEndScheduler( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* The structures and methods of manipulating the MPU are contained within the
|
||||
* port layer.
|
||||
*
|
||||
* Fills the xMPUSettings structure with the memory region information
|
||||
* contained in xRegions.
|
||||
*/
|
||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||
struct xMEMORY_REGION;
|
||||
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PORTABLE_H */
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef PROJDEFS_H
|
||||
#define PROJDEFS_H
|
||||
|
||||
/*
|
||||
* Defines the prototype to which task functions must conform. Defined in this
|
||||
* file to ensure the type is known before portable.h is included.
|
||||
*/
|
||||
typedef void (*TaskFunction_t)( void * );
|
||||
|
||||
/* Converts a time in milliseconds to a time in ticks. This macro can be
|
||||
overridden by a macro of the same name defined in FreeRTOSConfig.h in case the
|
||||
definition here is not suitable for your application. */
|
||||
#ifndef pdMS_TO_TICKS
|
||||
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000 ) )
|
||||
#endif
|
||||
|
||||
#define pdFALSE ( ( BaseType_t ) 0 )
|
||||
#define pdTRUE ( ( BaseType_t ) 1 )
|
||||
|
||||
#define pdPASS ( pdTRUE )
|
||||
#define pdFAIL ( pdFALSE )
|
||||
#define errQUEUE_EMPTY ( ( BaseType_t ) 0 )
|
||||
#define errQUEUE_FULL ( ( BaseType_t ) 0 )
|
||||
|
||||
/* FreeRTOS error definitions. */
|
||||
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
|
||||
#define errQUEUE_BLOCKED ( -4 )
|
||||
#define errQUEUE_YIELD ( -5 )
|
||||
|
||||
/* Macros used for basic data corruption checks. */
|
||||
#ifndef configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES
|
||||
#define configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 0
|
||||
#endif
|
||||
|
||||
#if( configUSE_16_BIT_TICKS == 1 )
|
||||
#define pdINTEGRITY_CHECK_VALUE 0x5a5a
|
||||
#else
|
||||
#define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL
|
||||
#endif
|
||||
|
||||
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
|
||||
itself. */
|
||||
#define pdFREERTOS_ERRNO_NONE 0 /* No errors */
|
||||
#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
|
||||
#define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */
|
||||
#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */
|
||||
#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */
|
||||
#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */
|
||||
#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */
|
||||
#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */
|
||||
#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */
|
||||
#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */
|
||||
#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */
|
||||
#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */
|
||||
#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */
|
||||
#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */
|
||||
#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */
|
||||
#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */
|
||||
#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */
|
||||
#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */
|
||||
#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */
|
||||
#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */
|
||||
#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */
|
||||
#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */
|
||||
#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */
|
||||
#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */
|
||||
#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */
|
||||
#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */
|
||||
#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */
|
||||
#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */
|
||||
#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */
|
||||
#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */
|
||||
#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */
|
||||
#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */
|
||||
#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */
|
||||
#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */
|
||||
#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */
|
||||
#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */
|
||||
#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */
|
||||
#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
|
||||
#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
|
||||
|
||||
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
|
||||
itself. */
|
||||
#define pdFREERTOS_LITTLE_ENDIAN 0
|
||||
#define pdFREERTOS_BIG_ENDIAN 1
|
||||
|
||||
/* Re-defining endian values for generic naming. */
|
||||
#define pdLITTLE_ENDIAN pdFREERTOS_LITTLE_ENDIAN
|
||||
#define pdBIG_ENDIAN pdFREERTOS_BIG_ENDIAN
|
||||
|
||||
|
||||
#endif /* PROJDEFS_H */
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,143 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef STACK_MACROS_H
|
||||
#define STACK_MACROS_H
|
||||
|
||||
/*
|
||||
* Call the stack overflow hook function if the stack of the task being swapped
|
||||
* out is currently overflowed, or looks like it might have overflowed in the
|
||||
* past.
|
||||
*
|
||||
* Setting configCHECK_FOR_STACK_OVERFLOW to 1 will cause the macro to check
|
||||
* the current stack state only - comparing the current top of stack value to
|
||||
* the stack limit. Setting configCHECK_FOR_STACK_OVERFLOW to greater than 1
|
||||
* will also cause the last few stack bytes to be checked to ensure the value
|
||||
* to which the bytes were set when the task was created have not been
|
||||
* overwritten. Note this second test does not guarantee that an overflowed
|
||||
* stack will always be recognised.
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB[uxPsrId]->pxTopOfStack <= pxCurrentTCB[uxPsrId]->pxStack ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB[uxPsrId], pxCurrentTCB[uxPsrId]->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
\
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
|
||||
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||
\
|
||||
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
int8_t *pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
|
||||
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE }; \
|
||||
\
|
||||
\
|
||||
pcEndOfStack -= sizeof( ucExpectedStackBytes ); \
|
||||
\
|
||||
/* Has the extremity of the task stack ever been written over? */ \
|
||||
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Remove stack overflow macro if not being used. */
|
||||
#ifndef taskCHECK_FOR_STACK_OVERFLOW
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* STACK_MACROS_H */
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
#ifndef FREERTOS_STDINT
|
||||
#define FREERTOS_STDINT
|
||||
|
||||
/*******************************************************************************
|
||||
* THIS IS NOT A FULL stdint.h IMPLEMENTATION - It only contains the definitions
|
||||
* necessary to build the FreeRTOS code. It is provided to allow FreeRTOS to be
|
||||
* built using compilers that do not provide their own stdint.h definition.
|
||||
*
|
||||
* To use this file:
|
||||
*
|
||||
* 1) Copy this file into the directory that contains your FreeRTOSConfig.h
|
||||
* header file, as that directory will already be in the compilers include
|
||||
* path.
|
||||
*
|
||||
* 2) Rename the copied file stdint.h.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef long int32_t;
|
||||
typedef unsigned long uint32_t;
|
||||
|
||||
#endif /* FREERTOS_STDINT */
|
|
@ -0,0 +1,866 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stream buffers are used to send a continuous stream of data from one task or
|
||||
* interrupt to another. Their implementation is light weight, making them
|
||||
* particularly suited for interrupt to task and core to core communication
|
||||
* scenarios.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xStreamBufferRead()) inside a critical section section and set the
|
||||
* receive block time to 0.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STREAM_BUFFER_H
|
||||
#define STREAM_BUFFER_H
|
||||
|
||||
#if defined( __cplusplus )
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type by which stream buffers are referenced. For example, a call to
|
||||
* xStreamBufferCreate() returns an StreamBufferHandle_t variable that can
|
||||
* then be used as a parameter to xStreamBufferSend(), xStreamBufferReceive(),
|
||||
* etc.
|
||||
*/
|
||||
typedef void * StreamBufferHandle_t;
|
||||
|
||||
|
||||
/**
|
||||
* message_buffer.h
|
||||
*
|
||||
<pre>
|
||||
StreamBufferHandle_t xStreamBufferCreate( size_t xBufferSizeBytes, size_t xTriggerLevelBytes );
|
||||
</pre>
|
||||
*
|
||||
* Creates a new stream buffer using dynamically allocated memory. See
|
||||
* xStreamBufferCreateStatic() for a version that uses statically allocated
|
||||
* memory (memory that is allocated at compile time).
|
||||
*
|
||||
* configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 or left undefined in
|
||||
* FreeRTOSConfig.h for xStreamBufferCreate() to be available.
|
||||
*
|
||||
* @param xBufferSizeBytes The total number of bytes the stream buffer will be
|
||||
* able to hold at any one time.
|
||||
*
|
||||
* @param xTriggerLevelBytes The number of bytes that must be in the stream
|
||||
* buffer before a task that is blocked on the stream buffer to wait for data is
|
||||
* moved out of the blocked state. For example, if a task is blocked on a read
|
||||
* of an empty stream buffer that has a trigger level of 1 then the task will be
|
||||
* unblocked when a single byte is written to the buffer or the task's block
|
||||
* time expires. As another example, if a task is blocked on a read of an empty
|
||||
* stream buffer that has a trigger level of 10 then the task will not be
|
||||
* unblocked until the stream buffer contains at least 10 bytes or the task's
|
||||
* block time expires. If a reading task's block time expires before the
|
||||
* trigger level is reached then the task will still receive however many bytes
|
||||
* are actually available. Setting a trigger level of 0 will result in a
|
||||
* trigger level of 1 being used. It is not valid to specify a trigger level
|
||||
* that is greater than the buffer size.
|
||||
*
|
||||
* @return If NULL is returned, then the stream buffer cannot be created
|
||||
* because there is insufficient heap memory available for FreeRTOS to allocate
|
||||
* the stream buffer data structures and storage area. A non-NULL value being
|
||||
* returned indicates that the stream buffer has been created successfully -
|
||||
* the returned value should be stored as the handle to the created stream
|
||||
* buffer.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
|
||||
void vAFunction( void )
|
||||
{
|
||||
StreamBufferHandle_t xStreamBuffer;
|
||||
const size_t xStreamBufferSizeBytes = 100, xTriggerLevel = 10;
|
||||
|
||||
// Create a stream buffer that can hold 100 bytes. The memory used to hold
|
||||
// both the stream buffer structure and the data in the stream buffer is
|
||||
// allocated dynamically.
|
||||
xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );
|
||||
|
||||
if( xStreamBuffer == NULL )
|
||||
{
|
||||
// There was not enough heap memory space available to create the
|
||||
// stream buffer.
|
||||
}
|
||||
else
|
||||
{
|
||||
// The stream buffer was created successfully and can now be used.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xStreamBufferCreate xStreamBufferCreate
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
#define xStreamBufferCreate( xBufferSizeBytes, xTriggerLevelBytes ) xStreamBufferGenericCreate( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE )
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
StreamBufferHandle_t xStreamBufferCreateStatic( size_t xBufferSizeBytes,
|
||||
size_t xTriggerLevelBytes,
|
||||
uint8_t *pucStreamBufferStorageArea,
|
||||
StaticStreamBuffer_t *pxStaticStreamBuffer );
|
||||
</pre>
|
||||
* Creates a new stream buffer using statically allocated memory. See
|
||||
* xStreamBufferCreate() for a version that uses dynamically allocated memory.
|
||||
*
|
||||
* configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h for
|
||||
* xStreamBufferCreateStatic() to be available.
|
||||
*
|
||||
* @param xBufferSizeBytes The size, in bytes, of the buffer pointed to by the
|
||||
* pucStreamBufferStorageArea parameter.
|
||||
*
|
||||
* @param xTriggerLevelBytes The number of bytes that must be in the stream
|
||||
* buffer before a task that is blocked on the stream buffer to wait for data is
|
||||
* moved out of the blocked state. For example, if a task is blocked on a read
|
||||
* of an empty stream buffer that has a trigger level of 1 then the task will be
|
||||
* unblocked when a single byte is written to the buffer or the task's block
|
||||
* time expires. As another example, if a task is blocked on a read of an empty
|
||||
* stream buffer that has a trigger level of 10 then the task will not be
|
||||
* unblocked until the stream buffer contains at least 10 bytes or the task's
|
||||
* block time expires. If a reading task's block time expires before the
|
||||
* trigger level is reached then the task will still receive however many bytes
|
||||
* are actually available. Setting a trigger level of 0 will result in a
|
||||
* trigger level of 1 being used. It is not valid to specify a trigger level
|
||||
* that is greater than the buffer size.
|
||||
*
|
||||
* @param pucStreamBufferStorageArea Must point to a uint8_t array that is at
|
||||
* least xBufferSizeBytes + 1 big. This is the array to which streams are
|
||||
* copied when they are written to the stream buffer.
|
||||
*
|
||||
* @param pxStaticStreamBuffer Must point to a variable of type
|
||||
* StaticStreamBuffer_t, which will be used to hold the stream buffer's data
|
||||
* structure.
|
||||
*
|
||||
* @return If the stream buffer is created successfully then a handle to the
|
||||
* created stream buffer is returned. If either pucStreamBufferStorageArea or
|
||||
* pxStaticstreamBuffer are NULL then NULL is returned.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
|
||||
// Used to dimension the array used to hold the streams. The available space
|
||||
// will actually be one less than this, so 999.
|
||||
#define STORAGE_SIZE_BYTES 1000
|
||||
|
||||
// Defines the memory that will actually hold the streams within the stream
|
||||
// buffer.
|
||||
static uint8_t ucStorageBuffer[ STORAGE_SIZE_BYTES ];
|
||||
|
||||
// The variable used to hold the stream buffer structure.
|
||||
StaticStreamBuffer_t xStreamBufferStruct;
|
||||
|
||||
void MyFunction( void )
|
||||
{
|
||||
StreamBufferHandle_t xStreamBuffer;
|
||||
const size_t xTriggerLevel = 1;
|
||||
|
||||
xStreamBuffer = xStreamBufferCreateStatic( sizeof( ucBufferStorage ),
|
||||
xTriggerLevel,
|
||||
ucBufferStorage,
|
||||
&xStreamBufferStruct );
|
||||
|
||||
// As neither the pucStreamBufferStorageArea or pxStaticStreamBuffer
|
||||
// parameters were NULL, xStreamBuffer will not be NULL, and can be used to
|
||||
// reference the created stream buffer in other stream buffer API calls.
|
||||
|
||||
// Other code that uses the stream buffer can go here.
|
||||
}
|
||||
|
||||
</pre>
|
||||
* \defgroup xStreamBufferCreateStatic xStreamBufferCreateStatic
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
#define xStreamBufferCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pucStreamBufferStorageArea, pxStaticStreamBuffer ) xStreamBufferGenericCreateStatic( xBufferSizeBytes, xTriggerLevelBytes, pdFALSE, pucStreamBufferStorageArea, pxStaticStreamBuffer )
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
||||
const void *pvTxData,
|
||||
size_t xDataLengthBytes,
|
||||
TickType_t xTicksToWait );
|
||||
<pre>
|
||||
*
|
||||
* Sends bytes to a stream buffer. The bytes are copied into the stream buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xStreamBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xStreamBufferSend() to write to a stream buffer from a task. Use
|
||||
* xStreamBufferSendFromISR() to write to a stream buffer from an interrupt
|
||||
* service routine (ISR).
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer to which a stream is
|
||||
* being sent.
|
||||
*
|
||||
* @param pvTxData A pointer to the buffer that holds the bytes to be copied
|
||||
* into the stream buffer.
|
||||
*
|
||||
* @param xDataLengthBytes The maximum number of bytes to copy from pvTxData
|
||||
* into the stream buffer.
|
||||
*
|
||||
* @param xTicksToWait The maximum amount of time the task should remain in the
|
||||
* Blocked state to wait for enough space to become available in the stream
|
||||
* buffer, should the stream buffer contain too little space to hold the
|
||||
* another xDataLengthBytes bytes. The block time is specified in tick periods,
|
||||
* so the absolute time it represents is dependent on the tick frequency. The
|
||||
* macro pdMS_TO_TICKS() can be used to convert a time specified in milliseconds
|
||||
* into a time specified in ticks. Setting xTicksToWait to portMAX_DELAY will
|
||||
* cause the task to wait indefinitely (without timing out), provided
|
||||
* INCLUDE_vTaskSuspend is set to 1 in FreeRTOSConfig.h. If a task times out
|
||||
* before it can write all xDataLengthBytes into the buffer it will still write
|
||||
* as many bytes as possible. A task does not use any CPU time when it is in
|
||||
* the blocked state.
|
||||
*
|
||||
* @return The number of bytes written to the stream buffer. If a task times
|
||||
* out before it can write all xDataLengthBytes into the buffer it will still
|
||||
* write as many bytes as possible.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
void vAFunction( StreamBufferHandle_t xStreamBuffer )
|
||||
{
|
||||
size_t xBytesSent;
|
||||
uint8_t ucArrayToSend[] = { 0, 1, 2, 3 };
|
||||
char *pcStringToSend = "String to send";
|
||||
const TickType_t x100ms = pdMS_TO_TICKS( 100 );
|
||||
|
||||
// Send an array to the stream buffer, blocking for a maximum of 100ms to
|
||||
// wait for enough space to be available in the stream buffer.
|
||||
xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) ucArrayToSend, sizeof( ucArrayToSend ), x100ms );
|
||||
|
||||
if( xBytesSent != sizeof( ucArrayToSend ) )
|
||||
{
|
||||
// The call to xStreamBufferSend() times out before there was enough
|
||||
// space in the buffer for the data to be written, but it did
|
||||
// successfully write xBytesSent bytes.
|
||||
}
|
||||
|
||||
// Send the string to the stream buffer. Return immediately if there is not
|
||||
// enough space in the buffer.
|
||||
xBytesSent = xStreamBufferSend( xStreamBuffer, ( void * ) pcStringToSend, strlen( pcStringToSend ), 0 );
|
||||
|
||||
if( xBytesSent != strlen( pcStringToSend ) )
|
||||
{
|
||||
// The entire string could not be added to the stream buffer because
|
||||
// there was not enough free space in the buffer, but xBytesSent bytes
|
||||
// were sent. Could try again to send the remaining bytes.
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xStreamBufferSend xStreamBufferSend
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
size_t xStreamBufferSend( StreamBufferHandle_t xStreamBuffer,
|
||||
const void *pvTxData,
|
||||
size_t xDataLengthBytes,
|
||||
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||
const void *pvTxData,
|
||||
size_t xDataLengthBytes,
|
||||
BaseType_t *pxHigherPriorityTaskWoken );
|
||||
<pre>
|
||||
*
|
||||
* Interrupt safe version of the API function that sends a stream of bytes to
|
||||
* the stream buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xStreamBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xStreamBufferSend() to write to a stream buffer from a task. Use
|
||||
* xStreamBufferSendFromISR() to write to a stream buffer from an interrupt
|
||||
* service routine (ISR).
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer to which a stream is
|
||||
* being sent.
|
||||
*
|
||||
* @param pvTxData A pointer to the data that is to be copied into the stream
|
||||
* buffer.
|
||||
*
|
||||
* @param xDataLengthBytes The maximum number of bytes to copy from pvTxData
|
||||
* into the stream buffer.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken It is possible that a stream buffer will
|
||||
* have a task blocked on it waiting for data. Calling
|
||||
* xStreamBufferSendFromISR() can make data available, and so cause a task that
|
||||
* was waiting for data to leave the Blocked state. If calling
|
||||
* xStreamBufferSendFromISR() causes a task to leave the Blocked state, and the
|
||||
* unblocked task has a priority higher than the currently executing task (the
|
||||
* task that was interrupted), then, internally, xStreamBufferSendFromISR()
|
||||
* will set *pxHigherPriorityTaskWoken to pdTRUE. If
|
||||
* xStreamBufferSendFromISR() sets this value to pdTRUE, then normally a
|
||||
* context switch should be performed before the interrupt is exited. This will
|
||||
* ensure that the interrupt returns directly to the highest priority Ready
|
||||
* state task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it
|
||||
* is passed into the function. See the example code below for an example.
|
||||
*
|
||||
* @return The number of bytes actually written to the stream buffer, which will
|
||||
* be less than xDataLengthBytes if the stream buffer didn't have enough free
|
||||
* space for all the bytes to be written.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
// A stream buffer that has already been created.
|
||||
StreamBufferHandle_t xStreamBuffer;
|
||||
|
||||
void vAnInterruptServiceRoutine( void )
|
||||
{
|
||||
size_t xBytesSent;
|
||||
char *pcStringToSend = "String to send";
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||
|
||||
// Attempt to send the string to the stream buffer.
|
||||
xBytesSent = xStreamBufferSendFromISR( xStreamBuffer,
|
||||
( void * ) pcStringToSend,
|
||||
strlen( pcStringToSend ),
|
||||
&xHigherPriorityTaskWoken );
|
||||
|
||||
if( xBytesSent != strlen( pcStringToSend ) )
|
||||
{
|
||||
// There was not enough free space in the stream buffer for the entire
|
||||
// string to be written, ut xBytesSent bytes were written.
|
||||
}
|
||||
|
||||
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||
// xStreamBufferSendFromISR() then a task that has a priority above the
|
||||
// priority of the currently executing task was unblocked and a context
|
||||
// switch should be performed to ensure the ISR returns to the unblocked
|
||||
// task. In most FreeRTOS ports this is done by simply passing
|
||||
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
|
||||
// variables value, and perform the context switch if necessary. Check the
|
||||
// documentation for the port in use for port specific instructions.
|
||||
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xStreamBufferSendFromISR xStreamBufferSendFromISR
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
size_t xStreamBufferSendFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||
const void *pvTxData,
|
||||
size_t xDataLengthBytes,
|
||||
BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
|
||||
void *pvRxData,
|
||||
size_t xBufferLengthBytes,
|
||||
TickType_t xTicksToWait );
|
||||
</pre>
|
||||
*
|
||||
* Receives bytes from a stream buffer.
|
||||
*
|
||||
* ***NOTE***: Uniquely among FreeRTOS objects, the stream buffer
|
||||
* implementation (so also the message buffer implementation, as message buffers
|
||||
* are built on top of stream buffers) assumes there is only one task or
|
||||
* interrupt that will write to the buffer (the writer), and only one task or
|
||||
* interrupt that will read from the buffer (the reader). It is safe for the
|
||||
* writer and reader to be different tasks or interrupts, but, unlike other
|
||||
* FreeRTOS objects, it is not safe to have multiple different writers or
|
||||
* multiple different readers. If there are to be multiple different writers
|
||||
* then the application writer must place each call to a writing API function
|
||||
* (such as xStreamBufferSend()) inside a critical section and set the send
|
||||
* block time to 0. Likewise, if there are to be multiple different readers
|
||||
* then the application writer must place each call to a reading API function
|
||||
* (such as xStreamBufferRead()) inside a critical section and set the receive
|
||||
* block time to 0.
|
||||
*
|
||||
* Use xStreamBufferReceive() to read from a stream buffer from a task. Use
|
||||
* xStreamBufferReceiveFromISR() to read from a stream buffer from an
|
||||
* interrupt service routine (ISR).
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer from which bytes are to
|
||||
* be received.
|
||||
*
|
||||
* @param pvRxData A pointer to the buffer into which the received bytes will be
|
||||
* copied.
|
||||
*
|
||||
* @param xBufferLengthBytes The length of the buffer pointed to by the
|
||||
* pvRxData parameter. This sets the maximum number of bytes to receive in one
|
||||
* call. xStreamBufferReceive will return as many bytes as possible up to a
|
||||
* maximum set by xBufferLengthBytes.
|
||||
*
|
||||
* @param xTicksToWait The maximum amount of time the task should remain in the
|
||||
* Blocked state to wait for data to become available if the stream buffer is
|
||||
* empty. xStreamBufferReceive() will return immediately if xTicksToWait is
|
||||
* zero. The block time is specified in tick periods, so the absolute time it
|
||||
* represents is dependent on the tick frequency. The macro pdMS_TO_TICKS() can
|
||||
* be used to convert a time specified in milliseconds into a time specified in
|
||||
* ticks. Setting xTicksToWait to portMAX_DELAY will cause the task to wait
|
||||
* indefinitely (without timing out), provided INCLUDE_vTaskSuspend is set to 1
|
||||
* in FreeRTOSConfig.h. A task does not use any CPU time when it is in the
|
||||
* Blocked state.
|
||||
*
|
||||
* @return The number of bytes actually read from the stream buffer, which will
|
||||
* be less than xBufferLengthBytes if the call to xStreamBufferReceive() timed
|
||||
* out before xBufferLengthBytes were available.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
void vAFunction( StreamBuffer_t xStreamBuffer )
|
||||
{
|
||||
uint8_t ucRxData[ 20 ];
|
||||
size_t xReceivedBytes;
|
||||
const TickType_t xBlockTime = pdMS_TO_TICKS( 20 );
|
||||
|
||||
// Receive up to another sizeof( ucRxData ) bytes from the stream buffer.
|
||||
// Wait in the Blocked state (so not using any CPU processing time) for a
|
||||
// maximum of 100ms for the full sizeof( ucRxData ) number of bytes to be
|
||||
// available.
|
||||
xReceivedBytes = xStreamBufferReceive( xStreamBuffer,
|
||||
( void * ) ucRxData,
|
||||
sizeof( ucRxData ),
|
||||
xBlockTime );
|
||||
|
||||
if( xReceivedBytes > 0 )
|
||||
{
|
||||
// A ucRxData contains another xRecievedBytes bytes of data, which can
|
||||
// be processed here....
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xStreamBufferReceive xStreamBufferReceive
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
size_t xStreamBufferReceive( StreamBufferHandle_t xStreamBuffer,
|
||||
void *pvRxData,
|
||||
size_t xBufferLengthBytes,
|
||||
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||
void *pvRxData,
|
||||
size_t xBufferLengthBytes,
|
||||
BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* An interrupt safe version of the API function that receives bytes from a
|
||||
* stream buffer.
|
||||
*
|
||||
* Use xStreamBufferReceive() to read bytes from a stream buffer from a task.
|
||||
* Use xStreamBufferReceiveFromISR() to read bytes from a stream buffer from an
|
||||
* interrupt service routine (ISR).
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer from which a stream
|
||||
* is being received.
|
||||
*
|
||||
* @param pvRxData A pointer to the buffer into which the received bytes are
|
||||
* copied.
|
||||
*
|
||||
* @param xBufferLengthBytes The length of the buffer pointed to by the
|
||||
* pvRxData parameter. This sets the maximum number of bytes to receive in one
|
||||
* call. xStreamBufferReceive will return as many bytes as possible up to a
|
||||
* maximum set by xBufferLengthBytes.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken It is possible that a stream buffer will
|
||||
* have a task blocked on it waiting for space to become available. Calling
|
||||
* xStreamBufferReceiveFromISR() can make space available, and so cause a task
|
||||
* that is waiting for space to leave the Blocked state. If calling
|
||||
* xStreamBufferReceiveFromISR() causes a task to leave the Blocked state, and
|
||||
* the unblocked task has a priority higher than the currently executing task
|
||||
* (the task that was interrupted), then, internally,
|
||||
* xStreamBufferReceiveFromISR() will set *pxHigherPriorityTaskWoken to pdTRUE.
|
||||
* If xStreamBufferReceiveFromISR() sets this value to pdTRUE, then normally a
|
||||
* context switch should be performed before the interrupt is exited. That will
|
||||
* ensure the interrupt returns directly to the highest priority Ready state
|
||||
* task. *pxHigherPriorityTaskWoken should be set to pdFALSE before it is
|
||||
* passed into the function. See the code example below for an example.
|
||||
*
|
||||
* @return The number of bytes read from the stream buffer, if any.
|
||||
*
|
||||
* Example use:
|
||||
<pre>
|
||||
// A stream buffer that has already been created.
|
||||
StreamBuffer_t xStreamBuffer;
|
||||
|
||||
void vAnInterruptServiceRoutine( void )
|
||||
{
|
||||
uint8_t ucRxData[ 20 ];
|
||||
size_t xReceivedBytes;
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Initialised to pdFALSE.
|
||||
|
||||
// Receive the next stream from the stream buffer.
|
||||
xReceivedBytes = xStreamBufferReceiveFromISR( xStreamBuffer,
|
||||
( void * ) ucRxData,
|
||||
sizeof( ucRxData ),
|
||||
&xHigherPriorityTaskWoken );
|
||||
|
||||
if( xReceivedBytes > 0 )
|
||||
{
|
||||
// ucRxData contains xReceivedBytes read from the stream buffer.
|
||||
// Process the stream here....
|
||||
}
|
||||
|
||||
// If xHigherPriorityTaskWoken was set to pdTRUE inside
|
||||
// xStreamBufferReceiveFromISR() then a task that has a priority above the
|
||||
// priority of the currently executing task was unblocked and a context
|
||||
// switch should be performed to ensure the ISR returns to the unblocked
|
||||
// task. In most FreeRTOS ports this is done by simply passing
|
||||
// xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the
|
||||
// variables value, and perform the context switch if necessary. Check the
|
||||
// documentation for the port in use for port specific instructions.
|
||||
taskYIELD_FROM_ISR( xHigherPriorityTaskWoken );
|
||||
}
|
||||
</pre>
|
||||
* \defgroup xStreamBufferReceiveFromISR xStreamBufferReceiveFromISR
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
size_t xStreamBufferReceiveFromISR( StreamBufferHandle_t xStreamBuffer,
|
||||
void *pvRxData,
|
||||
size_t xBufferLengthBytes,
|
||||
BaseType_t * const pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Deletes a stream buffer that was previously created using a call to
|
||||
* xStreamBufferCreate() or xStreamBufferCreateStatic(). If the stream
|
||||
* buffer was created using dynamic memory (that is, by xStreamBufferCreate()),
|
||||
* then the allocated memory is freed.
|
||||
*
|
||||
* A stream buffer handle must not be used after the stream buffer has been
|
||||
* deleted.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer to be deleted.
|
||||
*
|
||||
* \defgroup vStreamBufferDelete vStreamBufferDelete
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
void vStreamBufferDelete( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Queries a stream buffer to see if it is full. A stream buffer is full if it
|
||||
* does not have any free space, and therefore cannot accept any more data.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||
*
|
||||
* @return If the stream buffer is full then pdTRUE is returned. Otherwise
|
||||
* pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xStreamBufferIsFull xStreamBufferIsFull
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
BaseType_t xStreamBufferIsFull( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Queries a stream buffer to see if it is empty. A stream buffer is empty if
|
||||
* it does not contain any data.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||
*
|
||||
* @return If the stream buffer is empty then pdTRUE is returned. Otherwise
|
||||
* pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xStreamBufferIsEmpty xStreamBufferIsEmpty
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
BaseType_t xStreamBufferIsEmpty( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Resets a stream buffer to its initial, empty, state. Any data that was in
|
||||
* the stream buffer is discarded. A stream buffer can only be reset if there
|
||||
* are no tasks blocked waiting to either send to or receive from the stream
|
||||
* buffer.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer being reset.
|
||||
*
|
||||
* @return If the stream buffer is reset then pdPASS is returned. If there was
|
||||
* a task blocked waiting to send to or read from the stream buffer then the
|
||||
* stream buffer is not reset and pdFAIL is returned.
|
||||
*
|
||||
* \defgroup xStreamBufferReset xStreamBufferReset
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Queries a stream buffer to see how much free space it contains, which is
|
||||
* equal to the amount of data that can be sent to the stream buffer before it
|
||||
* is full.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||
*
|
||||
* @return The number of bytes that can be written to the stream buffer before
|
||||
* the stream buffer would be full.
|
||||
*
|
||||
* \defgroup xStreamBufferSpacesAvailable xStreamBufferSpacesAvailable
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
size_t xStreamBufferSpacesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer );
|
||||
</pre>
|
||||
*
|
||||
* Queries a stream buffer to see how much data it contains, which is equal to
|
||||
* the number of bytes that can be read from the stream buffer before the stream
|
||||
* buffer would be empty.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer being queried.
|
||||
*
|
||||
* @return The number of bytes that can be read from the stream buffer before
|
||||
* the stream buffer would be empty.
|
||||
*
|
||||
* \defgroup xStreamBufferBytesAvailable xStreamBufferBytesAvailable
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
size_t xStreamBufferBytesAvailable( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel );
|
||||
</pre>
|
||||
*
|
||||
* A stream buffer's trigger level is the number of bytes that must be in the
|
||||
* stream buffer before a task that is blocked on the stream buffer to
|
||||
* wait for data is moved out of the blocked state. For example, if a task is
|
||||
* blocked on a read of an empty stream buffer that has a trigger level of 1
|
||||
* then the task will be unblocked when a single byte is written to the buffer
|
||||
* or the task's block time expires. As another example, if a task is blocked
|
||||
* on a read of an empty stream buffer that has a trigger level of 10 then the
|
||||
* task will not be unblocked until the stream buffer contains at least 10 bytes
|
||||
* or the task's block time expires. If a reading task's block time expires
|
||||
* before the trigger level is reached then the task will still receive however
|
||||
* many bytes are actually available. Setting a trigger level of 0 will result
|
||||
* in a trigger level of 1 being used. It is not valid to specify a trigger
|
||||
* level that is greater than the buffer size.
|
||||
*
|
||||
* A trigger level is set when the stream buffer is created, and can be modified
|
||||
* using xStreamBufferSetTriggerLevel().
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer being updated.
|
||||
*
|
||||
* @param xTriggerLevel The new trigger level for the stream buffer.
|
||||
*
|
||||
* @return If xTriggerLevel was less than or equal to the stream buffer's length
|
||||
* then the trigger level will be updated and pdTRUE is returned. Otherwise
|
||||
* pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xStreamBufferSetTriggerLevel xStreamBufferSetTriggerLevel
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* For advanced users only.
|
||||
*
|
||||
* The sbSEND_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||
* data is sent to a message buffer or stream buffer. If there was a task that
|
||||
* was blocked on the message or stream buffer waiting for data to arrive then
|
||||
* the sbSEND_COMPLETED() macro sends a notification to the task to remove it
|
||||
* from the Blocked state. xStreamBufferSendCompletedFromISR() does the same
|
||||
* thing. It is provided to enable application writers to implement their own
|
||||
* version of sbSEND_COMPLETED(), and MUST NOT BE USED AT ANY OTHER TIME.
|
||||
*
|
||||
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||
* additional information.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer to which data was
|
||||
* written.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||
* initialised to pdFALSE before it is passed into
|
||||
* xStreamBufferSendCompletedFromISR(). If calling
|
||||
* xStreamBufferSendCompletedFromISR() removes a task from the Blocked state,
|
||||
* and the task has a priority above the priority of the currently running task,
|
||||
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||
* context switch should be performed before exiting the ISR.
|
||||
*
|
||||
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||
* Otherwise pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xStreamBufferSendCompletedFromISR xStreamBufferSendCompletedFromISR
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
BaseType_t xStreamBufferSendCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/**
|
||||
* stream_buffer.h
|
||||
*
|
||||
<pre>
|
||||
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken );
|
||||
</pre>
|
||||
*
|
||||
* For advanced users only.
|
||||
*
|
||||
* The sbRECEIVE_COMPLETED() macro is called from within the FreeRTOS APIs when
|
||||
* data is read out of a message buffer or stream buffer. If there was a task
|
||||
* that was blocked on the message or stream buffer waiting for data to arrive
|
||||
* then the sbRECEIVE_COMPLETED() macro sends a notification to the task to
|
||||
* remove it from the Blocked state. xStreamBufferReceiveCompletedFromISR()
|
||||
* does the same thing. It is provided to enable application writers to
|
||||
* implement their own version of sbRECEIVE_COMPLETED(), and MUST NOT BE USED AT
|
||||
* ANY OTHER TIME.
|
||||
*
|
||||
* See the example implemented in FreeRTOS/Demo/Minimal/MessageBufferAMP.c for
|
||||
* additional information.
|
||||
*
|
||||
* @param xStreamBuffer The handle of the stream buffer from which data was
|
||||
* read.
|
||||
*
|
||||
* @param pxHigherPriorityTaskWoken *pxHigherPriorityTaskWoken should be
|
||||
* initialised to pdFALSE before it is passed into
|
||||
* xStreamBufferReceiveCompletedFromISR(). If calling
|
||||
* xStreamBufferReceiveCompletedFromISR() removes a task from the Blocked state,
|
||||
* and the task has a priority above the priority of the currently running task,
|
||||
* then *pxHigherPriorityTaskWoken will get set to pdTRUE indicating that a
|
||||
* context switch should be performed before exiting the ISR.
|
||||
*
|
||||
* @return If a task was removed from the Blocked state then pdTRUE is returned.
|
||||
* Otherwise pdFALSE is returned.
|
||||
*
|
||||
* \defgroup xStreamBufferReceiveCompletedFromISR xStreamBufferReceiveCompletedFromISR
|
||||
* \ingroup StreamBufferManagement
|
||||
*/
|
||||
BaseType_t xStreamBufferReceiveCompletedFromISR( StreamBufferHandle_t xStreamBuffer, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/* Functions below here are not part of the public API. */
|
||||
StreamBufferHandle_t xStreamBufferGenericCreate( size_t xBufferSizeBytes,
|
||||
size_t xTriggerLevelBytes,
|
||||
BaseType_t xIsMessageBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
|
||||
size_t xTriggerLevelBytes,
|
||||
BaseType_t xIsMessageBuffer,
|
||||
uint8_t * const pucStreamBufferStorageArea,
|
||||
StaticStreamBuffer_t * const pxStaticStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#if( configUSE_TRACE_FACILITY == 1 )
|
||||
void vStreamBufferSetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer, UBaseType_t uxStreamBufferNumber ) PRIVILEGED_FUNCTION;
|
||||
UBaseType_t uxStreamBufferGetStreamBufferNumber( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
uint8_t ucStreamBufferGetStreamBufferType( StreamBufferHandle_t xStreamBuffer ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
#if defined( __cplusplus )
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined( STREAM_BUFFER_H ) */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,212 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "list.h"
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* PUBLIC LIST API documented in list.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
void vListInitialise( List_t * const pxList )
|
||||
{
|
||||
/* The list structure contains a list item which is used to mark the
|
||||
end of the list. To initialise the list the list end is inserted
|
||||
as the only list entry. */
|
||||
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||
|
||||
/* The list end value is the highest possible value in the list to
|
||||
ensure it remains at the end of the list. */
|
||||
pxList->xListEnd.xItemValue = portMAX_DELAY;
|
||||
|
||||
/* The list end next and previous pointers point to itself so we know
|
||||
when the list is empty. */
|
||||
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||
|
||||
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
|
||||
|
||||
/* Write known values into the list if
|
||||
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
|
||||
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListInitialiseItem( ListItem_t * const pxItem )
|
||||
{
|
||||
/* Make sure the list item is not recorded as being on a list. */
|
||||
pxItem->pvContainer = NULL;
|
||||
|
||||
/* Write known values into the list item if
|
||||
configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
|
||||
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
|
||||
{
|
||||
ListItem_t * const pxIndex = pxList->pxIndex;
|
||||
|
||||
/* Only effective when configASSERT() is also defined, these tests may catch
|
||||
the list data structures being overwritten in memory. They will not catch
|
||||
data errors caused by incorrect configuration or use of FreeRTOS. */
|
||||
listTEST_LIST_INTEGRITY( pxList );
|
||||
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
|
||||
|
||||
/* Insert a new list item into pxList, but rather than sort the list,
|
||||
makes the new list item the last item to be removed by a call to
|
||||
listGET_OWNER_OF_NEXT_ENTRY(). */
|
||||
pxNewListItem->pxNext = pxIndex;
|
||||
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
|
||||
|
||||
/* Only used during decision coverage testing. */
|
||||
mtCOVERAGE_TEST_DELAY();
|
||||
|
||||
pxIndex->pxPrevious->pxNext = pxNewListItem;
|
||||
pxIndex->pxPrevious = pxNewListItem;
|
||||
|
||||
/* Remember which list the item is in. */
|
||||
pxNewListItem->pvContainer = ( void * ) pxList;
|
||||
|
||||
( pxList->uxNumberOfItems )++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
|
||||
{
|
||||
ListItem_t *pxIterator;
|
||||
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
|
||||
|
||||
/* Only effective when configASSERT() is also defined, these tests may catch
|
||||
the list data structures being overwritten in memory. They will not catch
|
||||
data errors caused by incorrect configuration or use of FreeRTOS. */
|
||||
listTEST_LIST_INTEGRITY( pxList );
|
||||
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
|
||||
|
||||
/* Insert the new list item into the list, sorted in xItemValue order.
|
||||
|
||||
If the list already contains a list item with the same item value then the
|
||||
new list item should be placed after it. This ensures that TCB's which are
|
||||
stored in ready lists (all of which have the same xItemValue value) get a
|
||||
share of the CPU. However, if the xItemValue is the same as the back marker
|
||||
the iteration loop below will not end. Therefore the value is checked
|
||||
first, and the algorithm slightly modified if necessary. */
|
||||
if( xValueOfInsertion == portMAX_DELAY )
|
||||
{
|
||||
pxIterator = pxList->xListEnd.pxPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* *** NOTE ***********************************************************
|
||||
If you find your application is crashing here then likely causes are
|
||||
listed below. In addition see http://www.freertos.org/FAQHelp.html for
|
||||
more tips, and ensure configASSERT() is defined!
|
||||
http://www.freertos.org/a00110.html#configASSERT
|
||||
|
||||
1) Stack overflow -
|
||||
see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
|
||||
2) Incorrect interrupt priority assignment, especially on Cortex-M
|
||||
parts where numerically high priority values denote low actual
|
||||
interrupt priorities, which can seem counter intuitive. See
|
||||
http://www.freertos.org/RTOS-Cortex-M3-M4.html and the definition
|
||||
of configMAX_SYSCALL_INTERRUPT_PRIORITY on
|
||||
http://www.freertos.org/a00110.html
|
||||
3) Calling an API function from within a critical section or when
|
||||
the scheduler is suspended, or calling an API function that does
|
||||
not end in "FromISR" from an interrupt.
|
||||
4) Using a queue or semaphore before it has been initialised or
|
||||
before the scheduler has been started (are interrupts firing
|
||||
before vTaskStartScheduler() has been called?).
|
||||
**********************************************************************/
|
||||
|
||||
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */
|
||||
{
|
||||
/* There is nothing to do here, just iterating to the wanted
|
||||
insertion position. */
|
||||
}
|
||||
}
|
||||
|
||||
pxNewListItem->pxNext = pxIterator->pxNext;
|
||||
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
|
||||
pxNewListItem->pxPrevious = pxIterator;
|
||||
pxIterator->pxNext = pxNewListItem;
|
||||
|
||||
/* Remember which list the item is in. This allows fast removal of the
|
||||
item later. */
|
||||
pxNewListItem->pvContainer = ( void * ) pxList;
|
||||
|
||||
( pxList->uxNumberOfItems )++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
|
||||
{
|
||||
/* The list item knows which list it is in. Obtain the list from the list
|
||||
item. */
|
||||
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
|
||||
|
||||
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
|
||||
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
|
||||
|
||||
/* Only used during decision coverage testing. */
|
||||
mtCOVERAGE_TEST_DELAY();
|
||||
|
||||
/* Make sure the index is left pointing to a valid item. */
|
||||
if( pxList->pxIndex == pxItemToRemove )
|
||||
{
|
||||
pxList->pxIndex = pxItemToRemove->pxPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
pxItemToRemove->pvContainer = NULL;
|
||||
( pxList->uxNumberOfItems )--;
|
||||
|
||||
return pxList->uxNumberOfItems;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "FreeRTOS.h"
|
||||
#include "core_sync.h"
|
||||
#include "task.h"
|
||||
#include <clint.h>
|
||||
#include <encoding.h>
|
||||
#include <fpioa.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static StaticTask_t s_idle_task;
|
||||
static StackType_t s_idle_task_stack[configMINIMAL_STACK_SIZE];
|
||||
|
||||
void vApplicationIdleHook(void)
|
||||
{
|
||||
}
|
||||
|
||||
void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
|
||||
{
|
||||
/* Pass out a pointer to the StaticTask_t structure in which the Idle task's
|
||||
state will be stored. */
|
||||
*ppxIdleTaskTCBBuffer = &s_idle_task;
|
||||
|
||||
/* Pass out the array that will be used as the Idle task's stack. */
|
||||
*ppxIdleTaskStackBuffer = s_idle_task_stack;
|
||||
|
||||
/* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
|
||||
Note that, as the array is necessarily of type StackType_t,
|
||||
configMINIMAL_STACK_SIZE is specified in words, not bytes. */
|
||||
*pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
|
||||
}
|
||||
|
||||
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
|
||||
{
|
||||
configASSERT(!"Stackoverflow !");
|
||||
}
|
|
@ -0,0 +1,451 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*
|
||||
* A sample implementation of pvPortMalloc() and vPortFree() that combines
|
||||
* (coalescences) adjacent memory blocks as they are freed, and in so doing
|
||||
* limits memory fragmentation.
|
||||
*
|
||||
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
|
||||
* memory management pages of http://www.FreeRTOS.org for more information.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "atomic.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
|
||||
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
|
||||
#endif
|
||||
|
||||
/* Block sizes must not get too small. */
|
||||
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
|
||||
|
||||
/* Assumes 8bit bytes! */
|
||||
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
|
||||
|
||||
/* Allocate the memory for the heap. */
|
||||
#if( configAPPLICATION_ALLOCATED_HEAP == 1 )
|
||||
/* The application writer has already defined the array used for the RTOS
|
||||
heap - probably so it can be placed in a special segment or address. */
|
||||
extern uint8_t ucHeap[configTOTAL_HEAP_SIZE];
|
||||
#else
|
||||
static uint8_t ucHeap[configTOTAL_HEAP_SIZE];
|
||||
#endif /* configAPPLICATION_ALLOCATED_HEAP */
|
||||
|
||||
/* Define the linked list structure. This is used to link free blocks in order
|
||||
of their memory address. */
|
||||
typedef struct A_BLOCK_LINK
|
||||
{
|
||||
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
|
||||
size_t xBlockSize; /*<< The size of the free block. */
|
||||
} BlockLink_t;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Inserts a block of memory that is being freed into the correct position in
|
||||
* the list of free memory blocks. The block being freed will be merged with
|
||||
* the block in front it and/or the block behind it if the memory blocks are
|
||||
* adjacent to each other.
|
||||
*/
|
||||
static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert);
|
||||
|
||||
/*
|
||||
* Called automatically to setup the required heap structures the first time
|
||||
* pvPortMalloc() is called.
|
||||
*/
|
||||
static void prvHeapInit(void);
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The size of the structure placed at the beginning of each allocated memory
|
||||
block must by correctly byte aligned. */
|
||||
static const size_t xHeapStructSize = (sizeof(BlockLink_t) + ((size_t)(portBYTE_ALIGNMENT - 1))) & ~((size_t)portBYTE_ALIGNMENT_MASK);
|
||||
|
||||
/* Create a couple of list links to mark the start and end of the list. */
|
||||
static BlockLink_t xStart, *pxEnd = NULL;
|
||||
|
||||
/* Keeps track of the number of free bytes remaining, but says nothing about
|
||||
fragmentation. */
|
||||
static size_t xFreeBytesRemaining = 0U;
|
||||
static size_t xMinimumEverFreeBytesRemaining = 0U;
|
||||
|
||||
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
|
||||
member of an BlockLink_t structure is set then the block belongs to the
|
||||
application. When the bit is free the block is still part of the free heap
|
||||
space. */
|
||||
static size_t xBlockAllocatedBit = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void *pvPortMalloc(size_t xWantedSize)
|
||||
{
|
||||
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
|
||||
void *pvReturn = NULL;
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
/* If this is the first call to malloc then the heap will require
|
||||
initialisation to setup the list of free blocks. */
|
||||
if (pxEnd == NULL)
|
||||
{
|
||||
prvHeapInit();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Check the requested block size is not so large that the top bit is
|
||||
set. The top bit of the block size member of the BlockLink_t structure
|
||||
is used to determine who owns the block - the application or the
|
||||
kernel, so it must be free. */
|
||||
if ((xWantedSize & xBlockAllocatedBit) == 0)
|
||||
{
|
||||
/* The wanted size is increased so it can contain a BlockLink_t
|
||||
structure in addition to the requested amount of bytes. */
|
||||
if (xWantedSize > 0)
|
||||
{
|
||||
xWantedSize += xHeapStructSize;
|
||||
|
||||
/* Ensure that blocks are always aligned to the required number
|
||||
of bytes. */
|
||||
if ((xWantedSize & portBYTE_ALIGNMENT_MASK) != 0x00)
|
||||
{
|
||||
/* Byte alignment required. */
|
||||
xWantedSize += (portBYTE_ALIGNMENT - (xWantedSize & portBYTE_ALIGNMENT_MASK));
|
||||
configASSERT((xWantedSize & portBYTE_ALIGNMENT_MASK) == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
if ((xWantedSize > 0) && (xWantedSize <= xFreeBytesRemaining))
|
||||
{
|
||||
/* Traverse the list from the start (lowest address) block until
|
||||
one of adequate size is found. */
|
||||
pxPreviousBlock = &xStart;
|
||||
pxBlock = xStart.pxNextFreeBlock;
|
||||
while ((pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL))
|
||||
{
|
||||
pxPreviousBlock = pxBlock;
|
||||
pxBlock = pxBlock->pxNextFreeBlock;
|
||||
}
|
||||
|
||||
/* If the end marker was reached then a block of adequate size
|
||||
was not found. */
|
||||
if (pxBlock != pxEnd)
|
||||
{
|
||||
/* Return the memory space pointed to - jumping over the
|
||||
BlockLink_t structure at its start. */
|
||||
pvReturn = (void *)(((uint8_t *)pxPreviousBlock->pxNextFreeBlock) + xHeapStructSize);
|
||||
|
||||
/* This block is being returned for use so must be taken out
|
||||
of the list of free blocks. */
|
||||
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
||||
|
||||
/* If the block is larger than required it can be split into
|
||||
two. */
|
||||
if ((pxBlock->xBlockSize - xWantedSize) > heapMINIMUM_BLOCK_SIZE)
|
||||
{
|
||||
/* This block is to be split into two. Create a new
|
||||
block following the number of bytes requested. The void
|
||||
cast is used to prevent byte alignment warnings from the
|
||||
compiler. */
|
||||
pxNewBlockLink = (void *)(((uint8_t *)pxBlock) + xWantedSize);
|
||||
configASSERT((((size_t)pxNewBlockLink) & portBYTE_ALIGNMENT_MASK) == 0);
|
||||
|
||||
/* Calculate the sizes of two blocks split from the
|
||||
single block. */
|
||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
||||
pxBlock->xBlockSize = xWantedSize;
|
||||
|
||||
/* Insert the new block into the list of free blocks. */
|
||||
prvInsertBlockIntoFreeList(pxNewBlockLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
||||
|
||||
if (xFreeBytesRemaining < xMinimumEverFreeBytesRemaining)
|
||||
{
|
||||
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* The block is being returned - it is allocated and owned
|
||||
by the application and has no "next" block. */
|
||||
pxBlock->xBlockSize |= xBlockAllocatedBit;
|
||||
pxBlock->pxNextFreeBlock = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
traceMALLOC(pvReturn, xWantedSize);
|
||||
}
|
||||
(void)taskEXIT_CRITICAL();
|
||||
|
||||
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
{
|
||||
if (pvReturn == NULL)
|
||||
{
|
||||
extern void vApplicationMallocFailedHook(void);
|
||||
vApplicationMallocFailedHook();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
configASSERT((((size_t)pvReturn) & (size_t)portBYTE_ALIGNMENT_MASK) == 0);
|
||||
return pvReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortFree(void *pv)
|
||||
{
|
||||
uint8_t *puc = (uint8_t *)pv;
|
||||
BlockLink_t *pxLink;
|
||||
|
||||
if (pv != NULL)
|
||||
{
|
||||
/* The memory being freed will have an BlockLink_t structure immediately
|
||||
before it. */
|
||||
puc -= xHeapStructSize;
|
||||
|
||||
/* This casting is to keep the compiler from issuing warnings. */
|
||||
pxLink = (void *)puc;
|
||||
|
||||
/* Check the block is actually allocated. */
|
||||
configASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0);
|
||||
configASSERT(pxLink->pxNextFreeBlock == NULL);
|
||||
|
||||
if ((pxLink->xBlockSize & xBlockAllocatedBit) != 0)
|
||||
{
|
||||
if (pxLink->pxNextFreeBlock == NULL)
|
||||
{
|
||||
/* The block is being returned to the heap - it is no longer
|
||||
allocated. */
|
||||
pxLink->xBlockSize &= ~xBlockAllocatedBit;
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
/* Add this block to the list of free blocks. */
|
||||
xFreeBytesRemaining += pxLink->xBlockSize;
|
||||
traceFREE(pv, pxLink->xBlockSize);
|
||||
prvInsertBlockIntoFreeList(((BlockLink_t *)pxLink));
|
||||
}
|
||||
(void)taskEXIT_CRITICAL();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetFreeHeapSize(void)
|
||||
{
|
||||
return xFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetMinimumEverFreeHeapSize(void)
|
||||
{
|
||||
return xMinimumEverFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortInitialiseBlocks(void)
|
||||
{
|
||||
/* This just exists to keep the linker quiet. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHeapInit(void)
|
||||
{
|
||||
BlockLink_t *pxFirstFreeBlock;
|
||||
uint8_t *pucAlignedHeap;
|
||||
size_t uxAddress;
|
||||
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
|
||||
|
||||
/* Ensure the heap starts on a correctly aligned boundary. */
|
||||
uxAddress = (size_t)ucHeap;
|
||||
|
||||
if ((uxAddress & portBYTE_ALIGNMENT_MASK) != 0)
|
||||
{
|
||||
uxAddress += (portBYTE_ALIGNMENT - 1);
|
||||
uxAddress &= ~((size_t)portBYTE_ALIGNMENT_MASK);
|
||||
xTotalHeapSize -= uxAddress - (size_t)ucHeap;
|
||||
}
|
||||
|
||||
pucAlignedHeap = (uint8_t *)uxAddress;
|
||||
|
||||
/* xStart is used to hold a pointer to the first item in the list of free
|
||||
blocks. The void cast is used to prevent compiler warnings. */
|
||||
xStart.pxNextFreeBlock = (void *)pucAlignedHeap;
|
||||
xStart.xBlockSize = (size_t)0;
|
||||
|
||||
/* pxEnd is used to mark the end of the list of free blocks and is inserted
|
||||
at the end of the heap space. */
|
||||
uxAddress = ((size_t)pucAlignedHeap) + xTotalHeapSize;
|
||||
uxAddress -= xHeapStructSize;
|
||||
uxAddress &= ~((size_t)portBYTE_ALIGNMENT_MASK);
|
||||
pxEnd = (void *)uxAddress;
|
||||
pxEnd->xBlockSize = 0;
|
||||
pxEnd->pxNextFreeBlock = NULL;
|
||||
|
||||
/* To start with there is a single free block that is sized to take up the
|
||||
entire heap space, minus the space taken by pxEnd. */
|
||||
pxFirstFreeBlock = (void *)pucAlignedHeap;
|
||||
pxFirstFreeBlock->xBlockSize = uxAddress - (size_t)pxFirstFreeBlock;
|
||||
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
|
||||
|
||||
/* Only one block exists - and it covers the entire usable heap space. */
|
||||
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
|
||||
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
|
||||
|
||||
/* Work out the position of the top bit in a size_t variable. */
|
||||
xBlockAllocatedBit = ((size_t)1) << ((sizeof(size_t) * heapBITS_PER_BYTE) - 1);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert)
|
||||
{
|
||||
BlockLink_t *pxIterator;
|
||||
uint8_t *puc;
|
||||
|
||||
/* Iterate through the list until a block is found that has a higher address
|
||||
than the block being inserted. */
|
||||
for (pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock)
|
||||
{
|
||||
/* Nothing to do here, just iterate to the right position. */
|
||||
}
|
||||
|
||||
/* Do the block being inserted, and the block it is being inserted after
|
||||
make a contiguous block of memory? */
|
||||
puc = (uint8_t *)pxIterator;
|
||||
if ((puc + pxIterator->xBlockSize) == (uint8_t *)pxBlockToInsert)
|
||||
{
|
||||
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
|
||||
pxBlockToInsert = pxIterator;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
/* Do the block being inserted, and the block it is being inserted before
|
||||
make a contiguous block of memory? */
|
||||
puc = (uint8_t *)pxBlockToInsert;
|
||||
if ((puc + pxBlockToInsert->xBlockSize) == (uint8_t *)pxIterator->pxNextFreeBlock)
|
||||
{
|
||||
if (pxIterator->pxNextFreeBlock != pxEnd)
|
||||
{
|
||||
/* Form one big block from the two blocks. */
|
||||
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
|
||||
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBlockToInsert->pxNextFreeBlock = pxEnd;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
|
||||
}
|
||||
|
||||
/* If the block being inserted plugged a gab, so was merged with the block
|
||||
before and the block after, then it's pxNextFreeBlock pointer will have
|
||||
already been set, and should not be set here as that would make it point
|
||||
to itself. */
|
||||
if (pxIterator != pxBlockToInsert)
|
||||
{
|
||||
pxIterator->pxNextFreeBlock = pxBlockToInsert;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Implementation of functions defined in portable.h for the RISC-V port.
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include <atomic.h>
|
||||
#include <clint.h>
|
||||
#include <encoding.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysctl.h>
|
||||
#include <syslog.h>
|
||||
#include "core_sync.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "portmacro.h"
|
||||
#include "task.h"
|
||||
|
||||
/* A variable is used to keep track of the critical section nesting. This
|
||||
variable has to be stored as part of the task context and must be initialised to
|
||||
a non zero value to ensure interrupts don't inadvertently become unmasked before
|
||||
the scheduler starts. As it is stored as part of the task context it will
|
||||
automatically be set to 0 when the first task is started. */
|
||||
static UBaseType_t uxCriticalNesting[portNUM_PROCESSORS] = {[0 ... portNUM_PROCESSORS - 1] = 0xaaaaaaaa};
|
||||
PRIVILEGED_DATA static corelock_t xCoreLock = CORELOCK_INIT;
|
||||
|
||||
/* Contains context when starting scheduler, save all 31 registers */
|
||||
#ifdef __gracefulExit
|
||||
#error Not ported
|
||||
BaseType_t xStartContext[31] = {0};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handler for timer interrupt
|
||||
*/
|
||||
void vPortSysTickHandler(void);
|
||||
|
||||
/*
|
||||
* Setup the timer to generate the tick interrupts.
|
||||
*/
|
||||
void vPortSetupTimer(void);
|
||||
|
||||
/*
|
||||
* Used to catch tasks that attempt to return from their implementing function.
|
||||
*/
|
||||
static void prvTaskExitError(void);
|
||||
|
||||
UBaseType_t uxPortGetProcessorId()
|
||||
{
|
||||
return (UBaseType_t)read_csr(mhartid);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Sets and enable the timer interrupt */
|
||||
void vPortSetupTimer(void)
|
||||
{
|
||||
UBaseType_t uxPsrId = uxPortGetProcessorId();
|
||||
clint->mtimecmp[uxPsrId] = clint->mtime + (configTICK_CLOCK_HZ / configTICK_RATE_HZ);
|
||||
/* Enable timer and soft interupt */
|
||||
__asm volatile("csrs mie,%0" ::"r"(0x88));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Sets the next timer interrupt
|
||||
* Reads previous timer compare register, and adds tickrate */
|
||||
void prvSetNextTimerInterrupt(void)
|
||||
{
|
||||
UBaseType_t uxPsrId = uxPortGetProcessorId();
|
||||
clint->mtimecmp[uxPsrId] += (configTICK_CLOCK_HZ / configTICK_RATE_HZ);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void prvTaskExitError(void)
|
||||
{
|
||||
/* A function that implements a task must not exit or attempt to return to
|
||||
its caller as there is nothing to return to. If a task wants to exit it
|
||||
should instead call vTaskDelete( NULL ).
|
||||
|
||||
Artificially force an assert() to be triggered if configASSERT() is
|
||||
defined, then stop here so application writers can catch the error. */
|
||||
UBaseType_t uxPsrId = uxPortGetProcessorId();
|
||||
configASSERT(uxCriticalNesting[uxPsrId] == ~0UL);
|
||||
portDISABLE_INTERRUPTS();
|
||||
for (;;)
|
||||
;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Clear current interrupt mask and set given mask */
|
||||
void vPortClearInterruptMask(int mask)
|
||||
{
|
||||
__asm volatile("csrw mie, %0" ::"r"(mask));
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Set interrupt mask and return current interrupt enable register */
|
||||
int vPortSetInterruptMask(void)
|
||||
{
|
||||
int ret;
|
||||
__asm volatile("csrr %0,mie"
|
||||
: "=r"(ret));
|
||||
__asm volatile("csrc mie,%0" ::"i"(7));
|
||||
return ret;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* See header file for description.
|
||||
*/
|
||||
StackType_t* pxPortInitialiseStack(StackType_t* pxTopOfStack, TaskFunction_t pxCode, void* pvParameters)
|
||||
{
|
||||
/* Simulate the stack frame as it would be created by a context switch
|
||||
interrupt. */
|
||||
pxTopOfStack -= 64;
|
||||
memset(pxTopOfStack, 0, sizeof(StackType_t) * 64);
|
||||
|
||||
pxTopOfStack[0] = (portSTACK_TYPE)prvTaskExitError; /* Register ra */
|
||||
pxTopOfStack[1] = (portSTACK_TYPE)pxTopOfStack;
|
||||
pxTopOfStack[8] = (portSTACK_TYPE)pvParameters; /* Register a0 */
|
||||
pxTopOfStack[30] = 0; /* Register fsr */
|
||||
pxTopOfStack[31] = (portSTACK_TYPE)pxCode; /* Register mepc */
|
||||
|
||||
return pxTopOfStack;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
void vPortSysTickHandler(void)
|
||||
{
|
||||
core_sync_complete_context_switch(uxPortGetProcessorId());
|
||||
vTaskSwitchContext();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortEnterCritical(void)
|
||||
{
|
||||
if (!core_sync_is_in_progress(uxPortGetProcessorId()))
|
||||
vTaskEnterCritical();
|
||||
corelock_lock(&xCoreLock);
|
||||
}
|
||||
|
||||
void vPortExitCritical(void)
|
||||
{
|
||||
corelock_unlock(&xCoreLock);
|
||||
if (!core_sync_is_in_progress(uxPortGetProcessorId()))
|
||||
vTaskExitCritical();
|
||||
}
|
||||
|
||||
void vPortYield()
|
||||
{
|
||||
core_sync_request_context_switch(uxPortGetProcessorId());
|
||||
}
|
||||
|
||||
void vPortFatal(const char* file, int line, const char* message)
|
||||
{
|
||||
portDISABLE_INTERRUPTS();
|
||||
corelock_lock(&xCoreLock);
|
||||
LOGE("FreeRTOS", "(%s:%d) %s", file, line, message);
|
||||
exit(-1);
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
UBaseType_t uxPortGetCPUClock()
|
||||
{
|
||||
return (UBaseType_t)sysctl_cpu_get_freq();
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
# Copyright 2018 Canaan Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
||||
# All rights reserved
|
||||
|
||||
# VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||
|
||||
# This file is part of the FreeRTOS distribution and was contributed
|
||||
# to the project by Technolution B.V. (www.technolution.nl,
|
||||
# freertos-riscv@technolution.eu) under the terms of the FreeRTOS
|
||||
# contributors license.
|
||||
|
||||
# FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License (version 2) as published by the
|
||||
# Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||
|
||||
# ***************************************************************************
|
||||
# >>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||
# >>! distribute a combined work that includes FreeRTOS without being !<<
|
||||
# >>! obliged to provide the source code for proprietary components !<<
|
||||
# >>! outside of the FreeRTOS kernel. !<<
|
||||
# ***************************************************************************
|
||||
|
||||
# FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||
# link: http://www.freertos.org/a00114.html
|
||||
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * FreeRTOS provides completely free yet professionally developed, *
|
||||
# * robust, strictly quality controlled, supported, and cross *
|
||||
# * platform software that is more than just the market leader, it *
|
||||
# * is the industry's de facto standard. *
|
||||
# * *
|
||||
# * Help yourself get started quickly while simultaneously helping *
|
||||
# * to support the FreeRTOS project by purchasing a FreeRTOS *
|
||||
# * tutorial book, reference manual, or both: *
|
||||
# * http://www.FreeRTOS.org/Documentation *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
# http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
||||
# the FAQ page "My application does not run, what could be wrong?". Have you
|
||||
# defined configASSERT()?
|
||||
|
||||
# http://www.FreeRTOS.org/support - In return for receiving this top quality
|
||||
# embedded software for free we request you assist our global community by
|
||||
# participating in the support forum.
|
||||
|
||||
# http://www.FreeRTOS.org/training - Investing in training allows your team to
|
||||
# be as productive as possible as early as possible. Now you can receive
|
||||
# FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
||||
# Ltd, and the world's leading authority on the world's leading RTOS.
|
||||
|
||||
# http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
||||
# including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
||||
# compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
||||
|
||||
# http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
||||
# Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
||||
|
||||
# http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
||||
# Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
||||
# licenses offer ticketed support, indemnification and commercial middleware.
|
||||
|
||||
# http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
||||
# engineered and independently SIL3 certified version for use in safety and
|
||||
# mission critical applications that require provable dependability.
|
||||
|
||||
# 1 tab == 4 spaces!
|
||||
#
|
||||
|
||||
# include "encoding.h"
|
||||
|
||||
# define REGBYTES 8
|
||||
|
||||
.global xPortSysTickInt
|
||||
.global xPortStartScheduler
|
||||
.global vPortYield
|
||||
.global vTaskIncrementTick
|
||||
.global vPortEndScheduler
|
||||
.global xExitStack
|
||||
.global uxPortGetProcessorId
|
||||
|
||||
# /* Macro for saving task context */
|
||||
.macro portSAVE_CONTEXT
|
||||
.global pxCurrentTCB
|
||||
# /* make room in stack */
|
||||
addi sp, sp, -REGBYTES * 64
|
||||
|
||||
# /* Save Context */
|
||||
sd ra, 0 * REGBYTES(sp)
|
||||
sd sp, 1 * REGBYTES(sp)
|
||||
sd tp, 2 * REGBYTES(sp)
|
||||
sd t0, 3 * REGBYTES(sp)
|
||||
sd t1, 4 * REGBYTES(sp)
|
||||
sd t2, 5 * REGBYTES(sp)
|
||||
sd s0, 6 * REGBYTES(sp)
|
||||
sd s1, 7 * REGBYTES(sp)
|
||||
sd a0, 8 * REGBYTES(sp)
|
||||
sd a1, 9 * REGBYTES(sp)
|
||||
sd a2, 10 * REGBYTES(sp)
|
||||
sd a3, 11 * REGBYTES(sp)
|
||||
sd a4, 12 * REGBYTES(sp)
|
||||
sd a5, 13 * REGBYTES(sp)
|
||||
sd a6, 14 * REGBYTES(sp)
|
||||
sd a7, 15 * REGBYTES(sp)
|
||||
sd s2, 16 * REGBYTES(sp)
|
||||
sd s3, 17 * REGBYTES(sp)
|
||||
sd s4, 18 * REGBYTES(sp)
|
||||
sd s5, 19 * REGBYTES(sp)
|
||||
sd s6, 20 * REGBYTES(sp)
|
||||
sd s7, 21 * REGBYTES(sp)
|
||||
sd s8, 22 * REGBYTES(sp)
|
||||
sd s9, 23 * REGBYTES(sp)
|
||||
sd s10, 24 * REGBYTES(sp)
|
||||
sd s11, 25 * REGBYTES(sp)
|
||||
sd t3, 26 * REGBYTES(sp)
|
||||
sd t4, 27 * REGBYTES(sp)
|
||||
sd t5, 28 * REGBYTES(sp)
|
||||
sd t6, 29 * REGBYTES(sp)
|
||||
|
||||
frsr t0
|
||||
sd t0, 30 * REGBYTES(sp)
|
||||
|
||||
csrr t0, mepc
|
||||
sd t0, 31 * REGBYTES(sp)
|
||||
|
||||
fsd f0, ( 0 + 32) * REGBYTES(sp)
|
||||
fsd f1, ( 1 + 32) * REGBYTES(sp)
|
||||
fsd f2, ( 2 + 32) * REGBYTES(sp)
|
||||
fsd f3, ( 3 + 32) * REGBYTES(sp)
|
||||
fsd f4, ( 4 + 32) * REGBYTES(sp)
|
||||
fsd f5, ( 5 + 32) * REGBYTES(sp)
|
||||
fsd f6, ( 6 + 32) * REGBYTES(sp)
|
||||
fsd f7, ( 7 + 32) * REGBYTES(sp)
|
||||
fsd f8, ( 8 + 32) * REGBYTES(sp)
|
||||
fsd f9, ( 9 + 32) * REGBYTES(sp)
|
||||
fsd f10, (10 + 32) * REGBYTES(sp)
|
||||
fsd f11, (11 + 32) * REGBYTES(sp)
|
||||
fsd f12, (12 + 32) * REGBYTES(sp)
|
||||
fsd f13, (13 + 32) * REGBYTES(sp)
|
||||
fsd f14, (14 + 32) * REGBYTES(sp)
|
||||
fsd f15, (15 + 32) * REGBYTES(sp)
|
||||
fsd f16, (16 + 32) * REGBYTES(sp)
|
||||
fsd f17, (17 + 32) * REGBYTES(sp)
|
||||
fsd f18, (18 + 32) * REGBYTES(sp)
|
||||
fsd f19, (19 + 32) * REGBYTES(sp)
|
||||
fsd f20, (20 + 32) * REGBYTES(sp)
|
||||
fsd f21, (21 + 32) * REGBYTES(sp)
|
||||
fsd f22, (22 + 32) * REGBYTES(sp)
|
||||
fsd f23, (23 + 32) * REGBYTES(sp)
|
||||
fsd f24, (24 + 32) * REGBYTES(sp)
|
||||
fsd f25, (25 + 32) * REGBYTES(sp)
|
||||
fsd f26, (26 + 32) * REGBYTES(sp)
|
||||
fsd f27, (27 + 32) * REGBYTES(sp)
|
||||
fsd f28, (28 + 32) * REGBYTES(sp)
|
||||
fsd f29, (29 + 32) * REGBYTES(sp)
|
||||
fsd f30, (30 + 32) * REGBYTES(sp)
|
||||
fsd f31, (31 + 32) * REGBYTES(sp)
|
||||
|
||||
# /* Store current stackpointer in task control block (TCB) */
|
||||
la t0, pxCurrentTCB
|
||||
csrr t1, mhartid
|
||||
slli t1, t1, 3
|
||||
add t0, t0, t1
|
||||
|
||||
ld t0, 0x0(t0)
|
||||
sd sp, 0x0(t0)
|
||||
.endm
|
||||
|
||||
# /* Macro for restoring task context */
|
||||
.macro portRESTORE_CONTEXT
|
||||
.global pxCurrentTCB
|
||||
# /* Load stack pointer from the current TCB */
|
||||
la t0, pxCurrentTCB
|
||||
csrr t1, mhartid
|
||||
slli t1, t1, 3
|
||||
add t0, t0, t1
|
||||
|
||||
ld sp, 0x0(t0)
|
||||
ld sp, 0x0(sp)
|
||||
|
||||
ld t0, 30 * REGBYTES(sp)
|
||||
fssr t0
|
||||
|
||||
ld t0, 31 * REGBYTES(sp)
|
||||
csrw mepc, t0
|
||||
|
||||
# /* Run in machine mode */
|
||||
li t0, MSTATUS_MPP | MSTATUS_MPIE
|
||||
csrs mstatus, t0
|
||||
|
||||
# /* Restore registers */
|
||||
ld ra, 0 * REGBYTES(sp)
|
||||
ld sp, 1 * REGBYTES(sp)
|
||||
ld tp, 2 * REGBYTES(sp)
|
||||
ld t0, 3 * REGBYTES(sp)
|
||||
ld t1, 4 * REGBYTES(sp)
|
||||
ld t2, 5 * REGBYTES(sp)
|
||||
ld s0, 6 * REGBYTES(sp)
|
||||
ld s1, 7 * REGBYTES(sp)
|
||||
ld a0, 8 * REGBYTES(sp)
|
||||
ld a1, 9 * REGBYTES(sp)
|
||||
ld a2, 10 * REGBYTES(sp)
|
||||
ld a3, 11 * REGBYTES(sp)
|
||||
ld a4, 12 * REGBYTES(sp)
|
||||
ld a5, 13 * REGBYTES(sp)
|
||||
ld a6, 14 * REGBYTES(sp)
|
||||
ld a7, 15 * REGBYTES(sp)
|
||||
ld s2, 16 * REGBYTES(sp)
|
||||
ld s3, 17 * REGBYTES(sp)
|
||||
ld s4, 18 * REGBYTES(sp)
|
||||
ld s5, 19 * REGBYTES(sp)
|
||||
ld s6, 20 * REGBYTES(sp)
|
||||
ld s7, 21 * REGBYTES(sp)
|
||||
ld s8, 22 * REGBYTES(sp)
|
||||
ld s9, 23 * REGBYTES(sp)
|
||||
ld s10, 24 * REGBYTES(sp)
|
||||
ld s11, 25 * REGBYTES(sp)
|
||||
ld t3, 26 * REGBYTES(sp)
|
||||
ld t4, 27 * REGBYTES(sp)
|
||||
ld t5, 28 * REGBYTES(sp)
|
||||
ld t6, 29 * REGBYTES(sp)
|
||||
|
||||
fld f0, ( 0 + 32) * REGBYTES(sp)
|
||||
fld f1, ( 1 + 32) * REGBYTES(sp)
|
||||
fld f2, ( 2 + 32) * REGBYTES(sp)
|
||||
fld f3, ( 3 + 32) * REGBYTES(sp)
|
||||
fld f4, ( 4 + 32) * REGBYTES(sp)
|
||||
fld f5, ( 5 + 32) * REGBYTES(sp)
|
||||
fld f6, ( 6 + 32) * REGBYTES(sp)
|
||||
fld f7, ( 7 + 32) * REGBYTES(sp)
|
||||
fld f8, ( 8 + 32) * REGBYTES(sp)
|
||||
fld f9, ( 9 + 32) * REGBYTES(sp)
|
||||
fld f10, (10 + 32) * REGBYTES(sp)
|
||||
fld f11, (11 + 32) * REGBYTES(sp)
|
||||
fld f12, (12 + 32) * REGBYTES(sp)
|
||||
fld f13, (13 + 32) * REGBYTES(sp)
|
||||
fld f14, (14 + 32) * REGBYTES(sp)
|
||||
fld f15, (15 + 32) * REGBYTES(sp)
|
||||
fld f16, (16 + 32) * REGBYTES(sp)
|
||||
fld f17, (17 + 32) * REGBYTES(sp)
|
||||
fld f18, (18 + 32) * REGBYTES(sp)
|
||||
fld f19, (19 + 32) * REGBYTES(sp)
|
||||
fld f20, (20 + 32) * REGBYTES(sp)
|
||||
fld f21, (21 + 32) * REGBYTES(sp)
|
||||
fld f22, (22 + 32) * REGBYTES(sp)
|
||||
fld f23, (23 + 32) * REGBYTES(sp)
|
||||
fld f24, (24 + 32) * REGBYTES(sp)
|
||||
fld f25, (25 + 32) * REGBYTES(sp)
|
||||
fld f26, (26 + 32) * REGBYTES(sp)
|
||||
fld f27, (27 + 32) * REGBYTES(sp)
|
||||
fld f28, (28 + 32) * REGBYTES(sp)
|
||||
fld f29, (29 + 32) * REGBYTES(sp)
|
||||
fld f30, (30 + 32) * REGBYTES(sp)
|
||||
fld f31, (31 + 32) * REGBYTES(sp)
|
||||
|
||||
addi sp, sp, REGBYTES * 64
|
||||
mret
|
||||
.endm
|
||||
|
||||
xPortStartScheduler:
|
||||
jal vPortSetupTimer
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
vPortEndScheduler:
|
||||
ret
|
||||
|
||||
.section .text.systick, "ax", @progbits
|
||||
xPortSysTickInt:
|
||||
portSAVE_CONTEXT
|
||||
call vPortSysTickHandler
|
||||
portRESTORE_CONTEXT
|
|
@ -0,0 +1,162 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* FreeRTOS Kernel V10.0.1
|
||||
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* http://www.FreeRTOS.org
|
||||
* http://aws.amazon.com/freertos
|
||||
*
|
||||
* 1 tab == 4 spaces!
|
||||
*/
|
||||
|
||||
#ifndef PORTMACRO_H
|
||||
#define PORTMACRO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* Port specific definitions.
|
||||
*
|
||||
* The settings in this file configure FreeRTOS correctly for the
|
||||
* given hardware and compiler.
|
||||
*
|
||||
* These settings should not be altered.
|
||||
*-----------------------------------------------------------
|
||||
*/
|
||||
#include <encoding.h>
|
||||
/* Multi-Core */
|
||||
#define portNUM_PROCESSORS 2
|
||||
|
||||
/* Type definitions. */
|
||||
#define portCHAR char
|
||||
#define portFLOAT float
|
||||
#define portDOUBLE double
|
||||
#define portLONG long
|
||||
#define portSHORT short
|
||||
#define portBASE_TYPE long
|
||||
|
||||
#define portSTACK_TYPE uintptr_t
|
||||
#define portPOINTER_SIZE_TYPE uintptr_t
|
||||
|
||||
typedef portSTACK_TYPE StackType_t;
|
||||
typedef long BaseType_t;
|
||||
typedef unsigned long UBaseType_t;
|
||||
|
||||
#if( configUSE_16_BIT_TICKS == 1 )
|
||||
typedef uint16_t TickType_t;
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffff
|
||||
#else
|
||||
typedef uint32_t TickType_t;
|
||||
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Architecture specifics. */
|
||||
#define portSTACK_GROWTH ( -1 )
|
||||
#define portTICK_PERIOD_MS ( ( TickType_t ) (1000 / configTICK_RATE_HZ) )
|
||||
#ifdef __riscv64
|
||||
#define portBYTE_ALIGNMENT 8
|
||||
#else
|
||||
#define portBYTE_ALIGNMENT 4
|
||||
#endif
|
||||
#define portCRITICAL_NESTING_IN_TCB 1
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Scheduler utilities. */
|
||||
extern void vPortYield( void );
|
||||
#define portYIELD() vPortYield()
|
||||
|
||||
extern void vPortYieldFromISR(void);
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Architecture specific optimisations. */
|
||||
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
|
||||
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
|
||||
#endif
|
||||
|
||||
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
|
||||
|
||||
/* Check the configuration. */
|
||||
#if( configMAX_PRIORITIES > 32 )
|
||||
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
|
||||
#endif
|
||||
|
||||
/* Store/clear the ready priorities in a bit map. */
|
||||
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
|
||||
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( ( uxReadyPriorities ) ) )
|
||||
|
||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||
|
||||
/* Critical section management. */
|
||||
extern int vPortSetInterruptMask( void );
|
||||
extern void vPortClearInterruptMask( int );
|
||||
extern void vTaskEnterCritical( void );
|
||||
extern void vTaskExitCritical( void );
|
||||
extern UBaseType_t uxPortGetProcessorId(void);
|
||||
void prvSetNextTimerInterrupt();
|
||||
void vPortAddNewTaskToReadyListAsync(UBaseType_t uxPsrId, void* pxNewTaskHandle);
|
||||
|
||||
void vPortEnterCritical(void);
|
||||
void vPortExitCritical(void);
|
||||
|
||||
UBaseType_t uxPortGetCPUClock();
|
||||
|
||||
#define portGET_PROCESSOR_ID() uxPortGetProcessorId()
|
||||
|
||||
#define portDISABLE_INTERRUPTS() __asm volatile ( "csrc mstatus,8" )
|
||||
#define portENABLE_INTERRUPTS() __asm volatile ( "csrs mstatus,8" )
|
||||
#define portENTER_CRITICAL() vPortEnterCritical()
|
||||
#define portEXIT_CRITICAL() vPortExitCritical()
|
||||
#define portSET_INTERRUPT_MASK_FROM_ISR() vPortSetInterruptMask()
|
||||
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedStatusValue ) vPortClearInterruptMask( uxSavedStatusValue )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Task function macros as described on the FreeRTOS.org WEB site. */
|
||||
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||
|
||||
#define portNOP() __asm volatile ( " nop " )
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PORTMACRO_H */
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
int pthread_setcancelstate(int __state, int *__oldstate)
|
||||
{
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
|||
Each real time kernel port consists of three files that contain the core kernel
|
||||
components and are common to every port, and one or more files that are
|
||||
specific to a particular microcontroller and or compiler.
|
||||
|
||||
+ The FreeRTOS/Source directory contains the three files that are common to
|
||||
every port - list.c, queue.c and tasks.c. The kernel is contained within these
|
||||
three files. croutine.c implements the optional co-routine functionality - which
|
||||
is normally only used on very memory limited systems.
|
||||
|
||||
+ The FreeRTOS/Source/Portable directory contains the files that are specific to
|
||||
a particular microcontroller and or compiler.
|
||||
|
||||
+ The FreeRTOS/Source/include directory contains the real time kernel header
|
||||
files.
|
||||
|
||||
See the readme file in the FreeRTOS/Source/Portable directory for more
|
||||
information.
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
BasedOnStyle: WebKit
|
||||
BreakBeforeBraces: Allman
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
UseTab: Never
|
||||
PointerAlignment: Right
|
||||
|
||||
...
|
|
@ -1,171 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "target_config.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
typedef enum _datatype
|
||||
{
|
||||
dt_float32,
|
||||
dt_uint8
|
||||
} datatype_t;
|
||||
|
||||
struct padding
|
||||
{
|
||||
int32_t before;
|
||||
int32_t after;
|
||||
|
||||
int32_t sum() const noexcept { return before + after; }
|
||||
|
||||
static padding zero() noexcept { return {}; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct value_range
|
||||
{
|
||||
T min;
|
||||
T max;
|
||||
|
||||
static constexpr value_range<T> full() noexcept
|
||||
{
|
||||
return { std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max() };
|
||||
}
|
||||
};
|
||||
|
||||
typedef enum _reduce_op
|
||||
{
|
||||
reduce_mean,
|
||||
reduce_min,
|
||||
reduce_max,
|
||||
reduce_sum
|
||||
} reduce_op_t;
|
||||
|
||||
typedef enum _binary_op
|
||||
{
|
||||
binary_add,
|
||||
binary_sub,
|
||||
binary_mul,
|
||||
binary_div,
|
||||
binary_min,
|
||||
binary_max
|
||||
} binary_op_t;
|
||||
|
||||
typedef enum _unary_op
|
||||
{
|
||||
unary_abs,
|
||||
unary_ceil,
|
||||
unary_cos,
|
||||
unary_exp,
|
||||
unary_floor,
|
||||
unary_log,
|
||||
unary_neg,
|
||||
unary_rsqrt,
|
||||
unary_sin,
|
||||
unary_square
|
||||
} unary_op_t;
|
||||
|
||||
typedef enum _image_resize_mode
|
||||
{
|
||||
image_resize_bilinear,
|
||||
image_resize_nearest_neighbor
|
||||
} image_resize_mode_t;
|
||||
|
||||
typedef struct _quant_param
|
||||
{
|
||||
int32_t zero_point;
|
||||
float scale;
|
||||
} quant_param_t;
|
||||
|
||||
inline bool operator==(const quant_param_t &lhs, const quant_param_t &rhs) noexcept
|
||||
{
|
||||
return lhs.zero_point == rhs.zero_point && lhs.scale == rhs.scale;
|
||||
}
|
||||
|
||||
inline bool almost_equal(const quant_param_t &lhs, const quant_param_t &rhs) noexcept
|
||||
{
|
||||
return lhs.zero_point == rhs.zero_point && std::abs(lhs.scale - rhs.scale) <= std::numeric_limits<float>::epsilon();
|
||||
}
|
||||
|
||||
struct fixed_mul
|
||||
{
|
||||
float mul;
|
||||
int8_t shift;
|
||||
|
||||
int32_t rounded_mul() const noexcept { return (int32_t)roundf(mul); }
|
||||
};
|
||||
|
||||
typedef enum _memory_type
|
||||
{
|
||||
mem_const,
|
||||
mem_main,
|
||||
mem_k210_kpu
|
||||
} memory_type_t;
|
||||
|
||||
using runtime_shape_t = std::array<int, 4>;
|
||||
using runtime_paddings_t = std::array<padding, 4>;
|
||||
|
||||
struct scalar
|
||||
{
|
||||
datatype_t type;
|
||||
std::array<uint8_t, 4> storage;
|
||||
|
||||
scalar() = default;
|
||||
|
||||
template <class T>
|
||||
scalar(T &&value) { as<T>() = value; }
|
||||
|
||||
template <class T>
|
||||
T &as() noexcept { return *reinterpret_cast<T *>(storage.data()); }
|
||||
|
||||
template <class T>
|
||||
const T &as() const noexcept { return *reinterpret_cast<const T *>(storage.data()); }
|
||||
};
|
||||
|
||||
struct memory_range
|
||||
{
|
||||
memory_type_t memory_type;
|
||||
datatype_t datatype;
|
||||
uint32_t start;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
inline bool operator==(const padding &lhs, const padding &rhs) noexcept
|
||||
{
|
||||
return lhs.before == rhs.before && lhs.after == rhs.after;
|
||||
}
|
||||
|
||||
inline bool operator!=(const padding &lhs, const padding &rhs) noexcept
|
||||
{
|
||||
return lhs.before != rhs.before || lhs.after != rhs.after;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool operator==(const value_range<T> &lhs, const value_range<T> &rhs) noexcept
|
||||
{
|
||||
return lhs.min == rhs.min && lhs.max == rhs.max;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool operator!=(const value_range<T> &lhs, const value_range<T> &rhs) noexcept
|
||||
{
|
||||
return lhs.min != rhs.min || lhs.max != rhs.max;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
inline std::vector<uint8_t> read_file(const std::filesystem::path &filename)
|
||||
{
|
||||
std::ifstream infile(filename, std::ios::binary | std::ios::in);
|
||||
if (!infile.good())
|
||||
throw std::runtime_error("Cannot open file: " + filename.string());
|
||||
|
||||
infile.seekg(0, std::ios::end);
|
||||
size_t length = infile.tellg();
|
||||
infile.seekg(0, std::ios::beg);
|
||||
std::vector<uint8_t> data(length);
|
||||
infile.read(reinterpret_cast<char *>(data.data()), length);
|
||||
infile.close();
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../kernel_utils.h"
|
||||
#include <runtime/runtime_op_utility.h>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace kernels
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
inline void conv2d(const float *input, float *output, const float *weights, const float *bias, const runtime_shape_t &in_shape,
|
||||
int32_t out_channels, int32_t filter_h, int32_t filter_w, int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w,
|
||||
const padding &padding_h, const padding &padding_w, const value_range<float> &fused_activation)
|
||||
{
|
||||
const auto out_h = details::get_windowed_output_size(in_shape[1], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = details::get_windowed_output_size(in_shape[2], filter_w, stride_w, dilation_w, padding_w);
|
||||
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
int in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
int in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
int filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_y_end = std::min(filter_h, (in_shape[1] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_xSstart = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
int filter_x_end = std::min(filter_w, (in_shape[2] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
|
||||
for (int oc = 0; oc < out_channels; oc++)
|
||||
{
|
||||
auto w_oc = weights + (size_t)oc * filter_h * filter_w * in_shape[3];
|
||||
float value = bias[oc];
|
||||
|
||||
for (int ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int kx = filter_xSstart; kx < filter_x_end; kx++)
|
||||
{
|
||||
int in_y = in_y_origin + dilation_h * ky;
|
||||
int in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
auto in_pix = in_batch + ((size_t)in_y * in_shape[2] + in_x) * in_shape[3];
|
||||
auto w_pix = w_oc + ((size_t)ky * filter_w + kx) * in_shape[3];
|
||||
|
||||
for (int ic = 0; ic < in_shape[3]; ic++)
|
||||
value += in_pix[ic] * w_pix[ic];
|
||||
}
|
||||
}
|
||||
|
||||
*output++ = details::apply_activation(value, fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void depthwise_conv2d(const float *input, float *output, const float *weights, const float *bias, const runtime_shape_t &in_shape,
|
||||
int32_t filter_h, int32_t filter_w, int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w,
|
||||
const padding &padding_h, const padding &padding_w, const value_range<float> &fused_activation)
|
||||
{
|
||||
const auto out_h = details::get_windowed_output_size(in_shape[1], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = details::get_windowed_output_size(in_shape[2], filter_w, stride_w, dilation_w, padding_w);
|
||||
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
int in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
int in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
int filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_y_end = std::min(filter_h, (in_shape[1] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_xSstart = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
int filter_x_end = std::min(filter_w, (in_shape[2] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
|
||||
for (int oc = 0; oc < in_shape[3]; oc++)
|
||||
{
|
||||
auto w_oc = weights + (size_t)oc * filter_h * filter_w;
|
||||
float value = bias[oc];
|
||||
|
||||
for (int ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int kx = filter_xSstart; kx < filter_x_end; kx++)
|
||||
{
|
||||
int in_y = in_y_origin + dilation_h * ky;
|
||||
int in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
auto in_pix = in_batch + ((size_t)in_y * in_shape[2] + in_x) * in_shape[3];
|
||||
auto w_pix = w_oc + ((size_t)ky * filter_w + kx);
|
||||
|
||||
value += in_pix[oc] * w_pix[0];
|
||||
}
|
||||
}
|
||||
|
||||
*output++ = details::apply_activation(value, fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TBinaryOp, class TOutputOp>
|
||||
void reduce_window2d(const float *input, float *output, float init_value, const runtime_shape_t &in_shape,
|
||||
int32_t filter_h, int32_t filter_w, int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w,
|
||||
const padding &padding_h, const padding &padding_w, const value_range<float> &fused_activation, TBinaryOp &&binary_op, TOutputOp &&window_op)
|
||||
{
|
||||
const auto out_h = details::get_windowed_output_size(in_shape[1], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = details::get_windowed_output_size(in_shape[2], filter_w, stride_w, dilation_w, padding_w);
|
||||
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
int in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
int in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
int filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_y_end = std::min(filter_h, (in_shape[1] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_xSstart = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
int filter_x_end = std::min(filter_w, (in_shape[2] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
|
||||
for (int oc = 0; oc < in_shape[3]; oc++)
|
||||
{
|
||||
float value = init_value;
|
||||
int32_t kernel_count = 0;
|
||||
|
||||
for (int ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int kx = filter_xSstart; kx < filter_x_end; kx++)
|
||||
{
|
||||
int in_y = in_y_origin + dilation_h * ky;
|
||||
int in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
auto in_pix = in_batch + ((size_t)in_y * in_shape[2] + in_x) * in_shape[3];
|
||||
|
||||
value = binary_op(value, in_pix[oc]);
|
||||
kernel_count++;
|
||||
}
|
||||
}
|
||||
|
||||
*output++ = details::apply_activation(window_op(value, kernel_count), fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void quantized_conv2d(const uint8_t *input, uint8_t *output, const uint8_t *weights, const int32_t *bias, const runtime_shape_t &in_shape,
|
||||
int32_t out_channels, int32_t filter_h, int32_t filter_w, int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w,
|
||||
const padding &padding_h, const padding &padding_w, int32_t input_offset, int32_t filter_offset, int32_t output_mul, int32_t output_shift, int32_t output_offset)
|
||||
{
|
||||
const auto out_h = details::get_windowed_output_size(in_shape[1], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = details::get_windowed_output_size(in_shape[2], filter_w, stride_w, dilation_w, padding_w);
|
||||
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
int in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
int in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
int filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_y_end = std::min(filter_h, (in_shape[1] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_xSstart = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
int filter_x_end = std::min(filter_w, (in_shape[2] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
|
||||
for (int oc = 0; oc < out_channels; oc++)
|
||||
{
|
||||
auto w_oc = weights + (size_t)oc * filter_h * filter_w * in_shape[3];
|
||||
int32_t value = bias[oc];
|
||||
|
||||
for (int ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int kx = filter_xSstart; kx < filter_x_end; kx++)
|
||||
{
|
||||
int in_y = in_y_origin + dilation_h * ky;
|
||||
int in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
auto in_pix = in_batch + ((size_t)in_y * in_shape[2] + in_x) * in_shape[3];
|
||||
auto w_pix = w_oc + ((size_t)ky * filter_w + kx) * in_shape[3];
|
||||
|
||||
for (int ic = 0; ic < in_shape[3]; ic++)
|
||||
value += (in_pix[ic] - input_offset) * (w_pix[ic] - filter_offset);
|
||||
}
|
||||
}
|
||||
|
||||
value = runtime::mul_and_carry_shift(value, output_mul, output_shift) + output_offset;
|
||||
*output++ = (uint8_t)std::clamp(value, 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void quantized_depthwise_conv2d(const uint8_t *input, uint8_t *output, const uint8_t *weights, const int32_t *bias, const runtime_shape_t &in_shape,
|
||||
int32_t filter_h, int32_t filter_w, int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w,
|
||||
const padding &padding_h, const padding &padding_w, int32_t input_offset, int32_t filter_offset, int32_t output_mul, int32_t output_shift, int32_t output_offset)
|
||||
{
|
||||
const auto out_h = details::get_windowed_output_size(in_shape[1], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = details::get_windowed_output_size(in_shape[2], filter_w, stride_w, dilation_w, padding_w);
|
||||
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
int in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
int in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
int filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_y_end = std::min(filter_h, (in_shape[1] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
int filter_xSstart = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
int filter_x_end = std::min(filter_w, (in_shape[2] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
|
||||
for (int oc = 0; oc < in_shape[3]; oc++)
|
||||
{
|
||||
auto w_oc = weights + (size_t)oc * filter_h * filter_w;
|
||||
int32_t value = bias[oc];
|
||||
|
||||
for (int ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int kx = filter_xSstart; kx < filter_x_end; kx++)
|
||||
{
|
||||
int in_y = in_y_origin + dilation_h * ky;
|
||||
int in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
auto in_pix = in_batch + ((size_t)in_y * in_shape[2] + in_x) * in_shape[3];
|
||||
auto w_pix = w_oc + ((size_t)ky * filter_w + kx);
|
||||
|
||||
value += (in_pix[oc] - input_offset) * (w_pix[0] - filter_offset);
|
||||
}
|
||||
}
|
||||
|
||||
value = runtime::mul_and_carry_shift(value, output_mul, output_shift) + output_offset;
|
||||
*output++ = (uint8_t)std::clamp(value, 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,355 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../kernel_utils.h"
|
||||
#include <runtime/k210/k210_runtime_op_utility.h>
|
||||
#include <runtime/runtime_op_utility.h>
|
||||
#include <xtl/xspan.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace kernels
|
||||
{
|
||||
namespace k210
|
||||
{
|
||||
namespace details
|
||||
{
|
||||
template <class T>
|
||||
struct pool_partial_type;
|
||||
|
||||
template <>
|
||||
struct pool_partial_type<uint8_t>
|
||||
{
|
||||
using type = uint32_t;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct pool_partial_type<float>
|
||||
{
|
||||
using type = float;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using pool_partial_type_t = typename pool_partial_type<T>::type;
|
||||
}
|
||||
|
||||
inline void kpu_upload(const uint8_t *src, uint8_t *dest, const runtime_shape_t &in_shape)
|
||||
{
|
||||
using namespace runtime::k210;
|
||||
|
||||
if (in_shape[3] % 64 == 0)
|
||||
{
|
||||
std::copy(src, src + kernels::details::compute_size(in_shape), dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto layout = get_kpu_row_layout(in_shape[3]);
|
||||
auto fmap_size = get_kpu_bytes(in_shape[3], in_shape[2], in_shape[1]);
|
||||
|
||||
for (int32_t batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto batch_origin = dest + (size_t)batch * fmap_size;
|
||||
for (int32_t oc = 0; oc < in_shape[1]; oc++)
|
||||
{
|
||||
auto channel_origin = batch_origin + (size_t)oc / layout.groups * layout.row_len * in_shape[2] * 64 + (size_t)oc % layout.groups * layout.row_pitch;
|
||||
for (int32_t y = 0; y < in_shape[2]; y++)
|
||||
{
|
||||
auto y_origin = channel_origin + (size_t)y * layout.row_len * 64;
|
||||
std::copy(src, src + in_shape[3], y_origin);
|
||||
src += in_shape[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void kpu_download(const uint8_t *src, uint8_t *dest, const runtime_shape_t &in_shape)
|
||||
{
|
||||
using namespace runtime::k210;
|
||||
|
||||
if (in_shape[3] % 64 == 0)
|
||||
{
|
||||
std::copy(src, src + kernels::details::compute_size(in_shape), dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto layout = get_kpu_row_layout(in_shape[3]);
|
||||
auto fmap_size = get_kpu_bytes(in_shape[3], in_shape[2], in_shape[1]);
|
||||
|
||||
for (int32_t batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto batch_origin = src + (size_t)batch * fmap_size;
|
||||
for (int32_t oc = 0; oc < in_shape[1]; oc++)
|
||||
{
|
||||
auto channel_origin = batch_origin + (size_t)oc / layout.groups * layout.row_len * in_shape[2] * 64 + (size_t)oc % layout.groups * layout.row_pitch;
|
||||
for (int32_t y = 0; y < in_shape[2]; y++)
|
||||
{
|
||||
auto y_origin = channel_origin + (size_t)y * layout.row_len * 64;
|
||||
for (int32_t x = 0; x < in_shape[3]; x++)
|
||||
*dest++ = y_origin[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool IsDepthwise, int32_t FilterSize>
|
||||
void kpu_conv2d(const uint8_t *input, int64_t *workspace, uint8_t *output, const uint8_t *weights, int32_t in_h, int32_t in_w, int32_t in_channels, int32_t out_channels, uint8_t pad_value, int32_t arg_x,
|
||||
int32_t shift_x, int32_t arg_w, int32_t shift_w, int64_t arg_add, const runtime::k210::kpu_batchnorm_segment *batchnorm, const runtime::k210::kpu_activation_table_t &activation)
|
||||
{
|
||||
const auto channel_size = size_t(in_h) * in_w;
|
||||
// conv
|
||||
{
|
||||
auto out_it = workspace;
|
||||
const auto pad = FilterSize == 1 ? 0 : 1;
|
||||
const auto groups = IsDepthwise ? out_channels : 1;
|
||||
const auto g_ic = IsDepthwise ? 1 : in_channels / groups;
|
||||
const auto g_oc = IsDepthwise ? 1 : out_channels;
|
||||
|
||||
for (int32_t og = 0; og < groups; og++)
|
||||
{
|
||||
const uint8_t *w_group_p = weights + (size_t)og * g_oc * g_ic * FilterSize * FilterSize;
|
||||
|
||||
for (int32_t oc = 0; oc < g_oc; oc++)
|
||||
{
|
||||
const uint8_t *w_oc_p = w_group_p + (size_t)oc * g_ic * FilterSize * FilterSize;
|
||||
|
||||
for (int32_t oy = 0; oy < in_h; oy++)
|
||||
{
|
||||
for (int32_t ox = 0; ox < in_w; ox++)
|
||||
{
|
||||
const int32_t in_y_origin = oy - pad;
|
||||
const int32_t in_x_origin = ox - pad;
|
||||
int64_t value = 0;
|
||||
int64_t sum_x = 0, sum_w = 0;
|
||||
|
||||
for (int32_t ic = 0; ic < g_ic; ic++)
|
||||
{
|
||||
const uint8_t *in_c_p = input + ((size_t)og * g_ic + ic) * in_h * in_w;
|
||||
const uint8_t *w_ic_p = w_oc_p + (size_t)ic * FilterSize * FilterSize;
|
||||
|
||||
for (int32_t ky = 0; ky < FilterSize; ky++)
|
||||
{
|
||||
for (int32_t kx = 0; kx < FilterSize; kx++)
|
||||
{
|
||||
const int32_t in_y = in_y_origin + ky;
|
||||
const int32_t in_x = in_x_origin + kx;
|
||||
|
||||
uint8_t x;
|
||||
if (in_x < 0 || in_x >= in_w
|
||||
|| in_y < 0 || in_y >= in_h)
|
||||
x = pad_value;
|
||||
else
|
||||
x = in_c_p[in_y * in_w + in_x];
|
||||
|
||||
uint8_t w = w_ic_p[ky * FilterSize + kx];
|
||||
|
||||
sum_x += x;
|
||||
sum_w += w;
|
||||
value += (int32_t)x * w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out_it++ = value + (arg_x * sum_x >> shift_x) + (arg_w * sum_w >> shift_w) + arg_add * g_ic;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bn act
|
||||
{
|
||||
auto src_it = workspace;
|
||||
auto out_it = output;
|
||||
for (int32_t oc = 0; oc < out_channels; oc++)
|
||||
{
|
||||
const auto &bn = batchnorm[oc];
|
||||
for (size_t i = 0; i < channel_size; i++)
|
||||
{
|
||||
auto value = (*src_it++ * bn.mul >> bn.shift) + bn.add;
|
||||
auto &seg = *std::find_if(activation.rbegin(), activation.rend(), [value](const runtime::k210::kpu_activation_segment &seg) {
|
||||
return value > seg.start_x;
|
||||
});
|
||||
value = runtime::carry_shift<int64_t, true>((value - seg.start_x) * seg.mul, seg.shift) + seg.add;
|
||||
*out_it++ = (uint8_t)std::clamp(value, int64_t(0), int64_t(255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void kpu_pool2d(const T *input, T *output, int32_t in_h, int32_t in_w, int32_t in_channels, runtime::k210::kpu_pool_type_t pool_type)
|
||||
{
|
||||
using namespace runtime::k210;
|
||||
using partial_t = details::pool_partial_type_t<T>;
|
||||
|
||||
const auto filter = get_kpu_filter_size(pool_type);
|
||||
const auto stride = get_kpu_filter_stride(pool_type);
|
||||
const auto out_h = get_kpu_pool_output_size(in_h, pool_type);
|
||||
const auto out_w = get_kpu_pool_output_size(in_w, pool_type);
|
||||
|
||||
for (int32_t oc = 0; oc < in_channels; oc++)
|
||||
{
|
||||
auto in_c_p = input + (size_t)oc * in_h * in_w;
|
||||
|
||||
for (int32_t oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int32_t ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
const int32_t in_y_origin = oy * stride;
|
||||
const int32_t in_x_origin = ox * stride;
|
||||
partial_t value = 0;
|
||||
|
||||
switch (pool_type)
|
||||
{
|
||||
case kpu_pool_bypass:
|
||||
{
|
||||
const int32_t in_y = in_y_origin;
|
||||
const int32_t in_x = in_x_origin;
|
||||
|
||||
value = in_c_p[in_y * in_w + in_x];
|
||||
break;
|
||||
}
|
||||
case kpu_pool_max_2_s2:
|
||||
case kpu_pool_max_2_s1:
|
||||
case kpu_pool_max_4_s4:
|
||||
{
|
||||
value = std::numeric_limits<T>::lowest();
|
||||
for (int32_t ky = 0; ky < filter; ky++)
|
||||
{
|
||||
for (int32_t kx = 0; kx < filter; kx++)
|
||||
{
|
||||
const int32_t in_y = in_y_origin + ky;
|
||||
const int32_t in_x = in_x_origin + kx;
|
||||
partial_t in_v;
|
||||
|
||||
if (in_y < 0 || in_y >= in_h || in_x < 0 || in_x >= in_w)
|
||||
in_v = std::numeric_limits<T>::lowest();
|
||||
else
|
||||
in_v = in_c_p[in_y * in_w + in_x];
|
||||
|
||||
value = std::max(value, in_v);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case kpu_pool_mean_2_s2:
|
||||
case kpu_pool_mean_2_s1:
|
||||
case kpu_pool_mean_4_s4:
|
||||
{
|
||||
for (int32_t ky = 0; ky < filter; ky++)
|
||||
{
|
||||
for (int32_t kx = 0; kx < filter; kx++)
|
||||
{
|
||||
const int32_t in_y = std::clamp(in_y_origin + ky, 0, in_h - 1);
|
||||
const int32_t in_x = std::clamp(in_x_origin + kx, 0, in_w - 1);
|
||||
const T in_v = in_c_p[in_y * in_w + in_x];
|
||||
|
||||
value += in_v;
|
||||
}
|
||||
}
|
||||
|
||||
value /= filter * filter;
|
||||
break;
|
||||
}
|
||||
case kpu_pool_left_top_2_s2:
|
||||
case kpu_pool_left_top_4_s4:
|
||||
case kpu_pool_right_top_2_s2:
|
||||
{
|
||||
auto k_off = get_kpu_select_pool_offset(pool_type);
|
||||
const int32_t in_y = in_y_origin + k_off[0];
|
||||
const int32_t in_x = in_x_origin + k_off[1];
|
||||
partial_t in_v;
|
||||
|
||||
if (in_y < 0 || in_y >= in_h || in_x < 0 || in_x >= in_w)
|
||||
in_v = 0;
|
||||
else
|
||||
in_v = in_c_p[in_y * in_w + in_x];
|
||||
|
||||
value = in_v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*output++ = (T)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool IsDepthwise, int32_t FilterSize>
|
||||
void fake_kpu_conv2d(const float *input, float *output, const float *weights, const float *bias, int32_t in_h, int32_t in_w, int32_t in_channels, int32_t out_channels, xtl::span<const runtime::k210::piecewise_linear_segment> fused_activation)
|
||||
{
|
||||
const auto channel_size = size_t(in_h) * in_w;
|
||||
|
||||
const auto pad = FilterSize == 1 ? 0 : 1;
|
||||
const auto groups = IsDepthwise ? out_channels : 1;
|
||||
const auto g_ic = IsDepthwise ? 1 : in_channels / groups;
|
||||
const auto g_oc = IsDepthwise ? 1 : out_channels;
|
||||
|
||||
for (int32_t og = 0; og < groups; og++)
|
||||
{
|
||||
const auto *w_group_p = weights + (size_t)og * g_oc * g_ic * FilterSize * FilterSize;
|
||||
|
||||
for (int32_t oc = 0; oc < g_oc; oc++)
|
||||
{
|
||||
const auto *w_oc_p = w_group_p + (size_t)oc * g_ic * FilterSize * FilterSize;
|
||||
|
||||
for (int32_t oy = 0; oy < in_h; oy++)
|
||||
{
|
||||
for (int32_t ox = 0; ox < in_w; ox++)
|
||||
{
|
||||
const int32_t in_y_origin = oy - pad;
|
||||
const int32_t in_x_origin = ox - pad;
|
||||
const int32_t filter_y_start = std::max(0, -in_y_origin);
|
||||
const int32_t filter_y_end = std::min(FilterSize, in_h - in_y_origin);
|
||||
const int32_t filter_x_start = std::max(0, -in_x_origin);
|
||||
const int32_t filter_x_end = std::min(FilterSize, in_w - in_x_origin);
|
||||
float value = bias[og * g_oc + oc];
|
||||
|
||||
for (int32_t ic = 0; ic < g_ic; ic++)
|
||||
{
|
||||
const auto *in_c_p = input + ((size_t)og * g_ic + ic) * in_h * in_w;
|
||||
const auto *w_ic_p = w_oc_p + (size_t)ic * FilterSize * FilterSize;
|
||||
|
||||
for (int32_t ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int32_t kx = filter_x_start; kx < filter_x_end; kx++)
|
||||
{
|
||||
const int32_t in_y = in_y_origin + ky;
|
||||
const int32_t in_x = in_x_origin + kx;
|
||||
|
||||
const auto in_v = in_c_p[in_y * in_w + in_x];
|
||||
const auto w = w_ic_p[ky * FilterSize + kx];
|
||||
|
||||
value += in_v * w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto &seg = *std::find_if(fused_activation.rbegin(), fused_activation.rend(), [value](const runtime::k210::piecewise_linear_segment &seg) {
|
||||
return value > seg.start;
|
||||
});
|
||||
*output++ = value * seg.mul + seg.add;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <datatypes.h>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace kernels
|
||||
{
|
||||
inline size_t offset(const runtime_shape_t &shape, const runtime_shape_t &index)
|
||||
{
|
||||
return (((size_t)index[0] * shape[1] + index[1]) * shape[2] + index[2]) * shape[3] + index[3];
|
||||
}
|
||||
|
||||
namespace details
|
||||
{
|
||||
inline int32_t get_windowed_output_size(int32_t size, int32_t filter, int32_t stride, int32_t dilation, const padding &padding)
|
||||
{
|
||||
auto effective_filter_size = (filter - 1) * dilation + 1;
|
||||
return (size + padding.before + padding.after - effective_filter_size + stride) / stride;
|
||||
}
|
||||
|
||||
inline size_t compute_size(const runtime_shape_t &shape)
|
||||
{
|
||||
return size_t(shape[0]) * shape[1] * shape[2] * shape[3];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T apply_activation(T value, value_range<T> activation)
|
||||
{
|
||||
return std::clamp(value, activation.min, activation.max);
|
||||
}
|
||||
|
||||
inline runtime_shape_t get_reduced_offset(const runtime_shape_t &in_offset, const runtime_shape_t &reduced_shape)
|
||||
{
|
||||
runtime_shape_t off;
|
||||
for (size_t i = 0; i < in_offset.size(); i++)
|
||||
{
|
||||
if (in_offset[i] >= reduced_shape[i])
|
||||
off[i] = 0;
|
||||
else
|
||||
off[i] = in_offset[i];
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
template <class T, class TRange>
|
||||
struct default_ptr_getter
|
||||
{
|
||||
T *operator()(const TRange &range) const noexcept { return range; }
|
||||
};
|
||||
|
||||
template <int32_t Bits>
|
||||
int32_t to_signed(uint32_t value)
|
||||
{
|
||||
auto mask = uint32_t(1) << (Bits - 1);
|
||||
if (Bits != 32 && (value & mask) != 0)
|
||||
{
|
||||
auto sign = 0xFFFFFFFF << Bits;
|
||||
return (int)(value | sign);
|
||||
}
|
||||
|
||||
return (int32_t)value;
|
||||
}
|
||||
|
||||
template <int32_t Bits>
|
||||
int64_t to_signed(uint64_t value)
|
||||
{
|
||||
auto mask = uint64_t(1) << (Bits - 1);
|
||||
if ((value & mask) != 0)
|
||||
{
|
||||
auto sign = 0xFFFFFFFFFFFFFFFF << Bits;
|
||||
return (int64_t)(value | sign);
|
||||
}
|
||||
|
||||
return (int64_t)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,436 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../kernel_utils.h"
|
||||
#include <cmath>
|
||||
#include <runtime/runtime_op_utility.h>
|
||||
#include <xtl/xspan.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace kernels
|
||||
{
|
||||
namespace neutral
|
||||
{
|
||||
template <class TOp>
|
||||
void binary(const float *input_a, const float *input_b, float *output, const runtime_shape_t &in_a_shape,
|
||||
const runtime_shape_t &in_b_shape, const runtime_shape_t &out_shape, const value_range<float> &fused_activation, TOp &&op)
|
||||
{
|
||||
for (int32_t d0 = 0; d0 < out_shape[0]; d0++)
|
||||
{
|
||||
for (int32_t d1 = 0; d1 < out_shape[1]; d1++)
|
||||
{
|
||||
for (int32_t d2 = 0; d2 < out_shape[2]; d2++)
|
||||
{
|
||||
for (int32_t d3 = 0; d3 < out_shape[3]; d3++)
|
||||
{
|
||||
runtime_shape_t in_off = { d0, d1, d2, d3 };
|
||||
const auto in_a_off = kernels::details::get_reduced_offset(in_off, in_a_shape);
|
||||
const auto in_b_off = kernels::details::get_reduced_offset(in_off, in_b_shape);
|
||||
const auto a = input_a[offset(in_a_shape, in_a_off)];
|
||||
const auto b = input_b[offset(in_b_shape, in_b_off)];
|
||||
|
||||
output[offset(out_shape, in_off)] = kernels::details::apply_activation(op(a, b), fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TRange, class TPtrGetter = details::default_ptr_getter<uint8_t, TRange>>
|
||||
inline void concat(xtl::span<TRange> inputs, uint8_t *output, xtl::span<const int32_t> concat_dims, size_t inner_size, size_t outer_size, TPtrGetter getter = {})
|
||||
{
|
||||
for (size_t oc = 0; oc < outer_size; oc++)
|
||||
{
|
||||
for (size_t i = 0; i < inputs.size(); i++)
|
||||
{
|
||||
auto size = inner_size * concat_dims[i];
|
||||
auto src = getter(inputs[i]) + oc * size;
|
||||
std::copy(src, src + size, output);
|
||||
output += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void conv2d(const float *input, float *output, const float *weights, const float *bias, const runtime_shape_t &in_shape,
|
||||
int32_t groups, int32_t out_channels, int32_t filter_h, int32_t filter_w, int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w,
|
||||
const padding &padding_h, const padding &padding_w, const value_range<float> &fused_activation)
|
||||
{
|
||||
const auto out_h = details::get_windowed_output_size(in_shape[2], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = details::get_windowed_output_size(in_shape[3], filter_w, stride_w, dilation_w, padding_w);
|
||||
const auto g_ic = in_shape[1] / groups;
|
||||
const auto g_oc = out_channels / groups;
|
||||
|
||||
for (int32_t batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
const float *in_batch_p = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int32_t og = 0; og < groups; og++)
|
||||
{
|
||||
const float *in_group_p = in_batch_p + (size_t)og * g_ic * in_shape[2] * in_shape[3];
|
||||
const float *w_group_p = weights + (size_t)og * g_oc * g_ic * filter_h * filter_w;
|
||||
|
||||
for (int32_t oc = 0; oc < g_oc; oc++)
|
||||
{
|
||||
const float *w_oc_p = w_group_p + (size_t)oc * g_ic * filter_h * filter_w;
|
||||
|
||||
for (int32_t oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int32_t ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
const int32_t in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
const int32_t in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
const int32_t filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
const int32_t filter_y_end = std::min(filter_h, (in_shape[2] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
const int32_t filter_x_start = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
const int32_t filter_x_end = std::min(filter_w, (in_shape[3] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
float value = bias[og * g_oc + oc];
|
||||
|
||||
for (int32_t ic = 0; ic < g_ic; ic++)
|
||||
{
|
||||
const float *in_c_p = in_group_p + (size_t)ic * in_shape[2] * in_shape[3];
|
||||
const float *w_ic_p = w_oc_p + (size_t)ic * filter_h * filter_w;
|
||||
|
||||
for (int32_t ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int32_t kx = filter_x_start; kx < filter_x_end; kx++)
|
||||
{
|
||||
const int32_t in_y = in_y_origin + dilation_h * ky;
|
||||
const int32_t in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
const float in_v = in_c_p[in_y * in_shape[3] + in_x];
|
||||
const float w = w_ic_p[ky * filter_w + kx];
|
||||
|
||||
value += in_v * w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*output++ = details::apply_activation(value, fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TQ>
|
||||
void dequantize(const TQ *input, float *output, size_t count, const quant_param_t ¶m)
|
||||
{
|
||||
float div = 1.f / param.scale;
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
output[i] = (input[i] - param.zero_point) * div;
|
||||
}
|
||||
}
|
||||
|
||||
inline void matmul(const float *input_a, const float *input_b, float *output, const float *bias, int32_t a_rows, int32_t a_cols, int32_t b_cols, const value_range<float> &fused_activation)
|
||||
{
|
||||
for (size_t oy = 0; oy < a_rows; oy++)
|
||||
{
|
||||
for (size_t ox = 0; ox < b_cols; ox++)
|
||||
{
|
||||
float value = bias[ox];
|
||||
for (size_t i = 0; i < a_cols; i++)
|
||||
{
|
||||
const auto a = input_a[oy * a_cols + i];
|
||||
const auto b = input_b[i * b_cols + ox];
|
||||
value += a * b;
|
||||
}
|
||||
|
||||
output[oy * b_cols + ox] = details::apply_activation(value, fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void pad(const T *input, T *output, const runtime_shape_t &in_shape, const runtime_paddings_t &paddings, T pad_value)
|
||||
{
|
||||
runtime_shape_t out_shape = { in_shape[0] + paddings[0].sum(),
|
||||
in_shape[1] + paddings[1].sum(),
|
||||
in_shape[2] + paddings[2].sum(),
|
||||
in_shape[3] + paddings[3].sum() };
|
||||
|
||||
for (int d0 = 0; d0 < out_shape[0]; d0++)
|
||||
{
|
||||
auto d0_origin = -paddings[0].before;
|
||||
auto in0 = input + ((size_t)d0_origin + d0) * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int d1 = 0; d1 < out_shape[1]; d1++)
|
||||
{
|
||||
auto d1_origin = -paddings[1].before;
|
||||
auto in1 = in0 + ((size_t)d1_origin + d1) * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int d2 = 0; d2 < out_shape[2]; d2++)
|
||||
{
|
||||
auto d2_origin = -paddings[2].before;
|
||||
auto in2 = in1 + ((size_t)d2_origin + d2) * in_shape[3];
|
||||
|
||||
for (int d3 = 0; d3 < out_shape[3]; d3++)
|
||||
{
|
||||
auto d3_origin = -paddings[3].before;
|
||||
|
||||
if (d0 < paddings[0].before || d0 >= out_shape[0] - paddings[0].after
|
||||
|| d1 < paddings[1].before || d1 >= out_shape[1] - paddings[1].after
|
||||
|| d2 < paddings[2].before || d2 >= out_shape[2] - paddings[2].after
|
||||
|| d3 < paddings[3].before || d3 >= out_shape[3] - paddings[3].after)
|
||||
*output++ = pad_value;
|
||||
else
|
||||
*output++ = in2[d3_origin + d3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TQ>
|
||||
void quantize(const float *input, TQ *output, size_t count, const quant_param_t ¶m)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
int32_t tmp = (int32_t)roundf(input[i] * param.scale + param.zero_point);
|
||||
output[i] = std::clamp(tmp, (int32_t)std::numeric_limits<TQ>::lowest(), (int32_t)std::numeric_limits<TQ>::max());
|
||||
}
|
||||
}
|
||||
|
||||
template <class TReducer>
|
||||
void reduce(const float *input, float *output, float init_value, const runtime_shape_t &in_shape, const runtime_shape_t &reduced_shape, TReducer &&reducer)
|
||||
{
|
||||
std::fill(output, output + kernels::details::compute_size(reduced_shape), init_value);
|
||||
|
||||
for (int32_t d0 = 0; d0 < in_shape[0]; d0++)
|
||||
{
|
||||
for (int32_t d1 = 0; d1 < in_shape[1]; d1++)
|
||||
{
|
||||
for (int32_t d2 = 0; d2 < in_shape[2]; d2++)
|
||||
{
|
||||
for (int32_t d3 = 0; d3 < in_shape[3]; d3++)
|
||||
{
|
||||
runtime_shape_t in_off = { d0, d1, d2, d3 };
|
||||
auto out_off = kernels::details::get_reduced_offset(in_off, reduced_shape);
|
||||
const auto a = input[offset(in_shape, in_off)];
|
||||
auto &b = output[offset(reduced_shape, out_off)];
|
||||
b = reducer(b, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TOp>
|
||||
void unary(const float *input, float *output, size_t count, TOp &&op)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
output[i] = op(input[i]);
|
||||
}
|
||||
|
||||
template <class TBinaryOp, class TOutputOp>
|
||||
void reduce_window2d(const float *input, float *output, float init_value, const runtime_shape_t &in_shape, int32_t filter_h, int32_t filter_w,
|
||||
int32_t stride_h, int32_t stride_w, int32_t dilation_h, int32_t dilation_w, const padding &padding_h, const padding &padding_w,
|
||||
const value_range<float> &fused_activation, TBinaryOp &&binary_op, TOutputOp &&window_op)
|
||||
{
|
||||
const auto out_h = kernels::details::get_windowed_output_size(in_shape[2], filter_h, stride_h, dilation_h, padding_h);
|
||||
const auto out_w = kernels::details::get_windowed_output_size(in_shape[3], filter_w, stride_w, dilation_w, padding_w);
|
||||
runtime_shape_t out_shape { in_shape[0], in_shape[1], out_h, out_w };
|
||||
|
||||
for (int32_t batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
for (int32_t oc = 0; oc < in_shape[1]; oc++)
|
||||
{
|
||||
for (int32_t oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
for (int32_t ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
const int32_t in_y_origin = (oy * stride_h) - padding_h.before;
|
||||
const int32_t in_x_origin = (ox * stride_w) - padding_w.before;
|
||||
const int32_t filter_y_start = std::max(0, (-in_y_origin + dilation_h - 1) / dilation_h);
|
||||
const int32_t filter_y_end = std::min(filter_h, (in_shape[2] - in_y_origin + dilation_h - 1) / dilation_h);
|
||||
const int32_t filter_x_start = std::max(0, (-in_x_origin + dilation_w - 1) / dilation_w);
|
||||
const int32_t filter_x_end = std::min(filter_w, (in_shape[3] - in_x_origin + dilation_w - 1) / dilation_w);
|
||||
float value = init_value;
|
||||
int32_t kernel_count = 0;
|
||||
|
||||
for (int32_t ky = filter_y_start; ky < filter_y_end; ky++)
|
||||
{
|
||||
for (int32_t kx = filter_x_start; kx < filter_x_end; kx++)
|
||||
{
|
||||
const int32_t in_y = in_y_origin + dilation_h * ky;
|
||||
const int32_t in_x = in_x_origin + dilation_w * kx;
|
||||
|
||||
const float in_v = input[offset(in_shape, { batch, oc, in_y, in_x })];
|
||||
|
||||
value = binary_op(value, in_v);
|
||||
kernel_count++;
|
||||
}
|
||||
}
|
||||
|
||||
output[offset(out_shape, { batch, oc, oy, ox })] = kernels::details::apply_activation(window_op(value, kernel_count), fused_activation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void resize_nearest_neighbor(const T *input, T *output, const runtime_shape_t &in_shape, int32_t out_h, int32_t out_w)
|
||||
{
|
||||
auto height_scale = (float)in_shape[2] / out_h;
|
||||
auto width_scale = (float)in_shape[3] / out_w;
|
||||
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oc = 0; oc < in_shape[1]; oc++)
|
||||
{
|
||||
auto in_c = in_batch + oc * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
auto in_y = std::min((int32_t)floorf(oy * height_scale), in_shape[2] - 1);
|
||||
auto in_row = in_c + in_y * in_shape[3];
|
||||
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
auto in_x = std::min((int32_t)floorf(ox * width_scale), in_shape[3] - 1);
|
||||
*output++ = in_row[in_x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void resize_bilinear(const float *input, float *output, const runtime_shape_t &in_shape, int32_t out_h, int32_t out_w, bool align_corners)
|
||||
{
|
||||
auto height_scale = (float)in_shape[2] / out_h;
|
||||
auto width_scale = (float)in_shape[3] / out_w;
|
||||
if (align_corners && out_h > 1)
|
||||
height_scale = (float)(in_shape[2] - 1) / (out_h - 1);
|
||||
if (align_corners && out_w > 1)
|
||||
width_scale = (float)(in_shape[3] - 1) / (out_w - 1);
|
||||
|
||||
auto destIdx = 0;
|
||||
for (int batch = 0; batch < in_shape[0]; batch++)
|
||||
{
|
||||
auto in_batch = input + (size_t)batch * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oc = 0; oc < in_shape[1]; oc++)
|
||||
{
|
||||
auto in_c = in_batch + (size_t)oc * in_shape[2] * in_shape[3];
|
||||
|
||||
for (int oy = 0; oy < out_h; oy++)
|
||||
{
|
||||
auto in_y = oy * height_scale;
|
||||
auto in_y0 = (int)floorf(in_y);
|
||||
auto in_y1 = std::min(in_y0 + 1, in_shape[2] - 1);
|
||||
|
||||
for (int ox = 0; ox < out_w; ox++)
|
||||
{
|
||||
auto in_x = ox * width_scale;
|
||||
auto in_x0 = (int)floorf(in_x);
|
||||
auto in_x1 = std::min(in_x0 + 1, in_shape[3] - 1);
|
||||
|
||||
auto v0 = in_c[in_y0 * in_shape[3] + in_x0];
|
||||
auto v1 = in_c[in_y1 * in_shape[3] + in_x0];
|
||||
auto v2 = in_c[in_y0 * in_shape[3] + in_x1];
|
||||
auto v3 = in_c[in_y1 * in_shape[3] + in_x1];
|
||||
|
||||
auto a0 = (1 - (in_y - in_y0)) * (1 - (in_x - in_x0));
|
||||
auto a1 = (in_y - in_y0) * (1 - (in_x - in_x0));
|
||||
auto a2 = (1 - (in_y - in_y0)) * (in_x - in_x0);
|
||||
auto a3 = (in_y - in_y0) * (in_x - in_x0);
|
||||
|
||||
output[destIdx++] = v0 * a0 + v1 * a1 + v2 * a2 + v3 * a3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void softmax(const float *input, float *output, float beta, int32_t outer_size, size_t inner_size)
|
||||
{
|
||||
for (size_t batch = 0; batch < outer_size; batch++)
|
||||
{
|
||||
auto src = input + batch * inner_size;
|
||||
auto dest = output + batch * inner_size;
|
||||
|
||||
auto max = *std::max_element(src, src + inner_size);
|
||||
float sum = 0;
|
||||
|
||||
for (size_t i = 0; i < inner_size; i++)
|
||||
{
|
||||
auto value = expf((src[i] - max) * beta);
|
||||
sum += value;
|
||||
dest[i] = value;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < inner_size; i++)
|
||||
dest[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void transpose(const T *input, T *output, const runtime_shape_t &in_shape, const runtime_shape_t &perm)
|
||||
{
|
||||
runtime_shape_t out_shape;
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
out_shape[i] = in_shape[perm[i]];
|
||||
|
||||
runtime_shape_t i, o;
|
||||
for (o[3] = 0; o[3] < out_shape[3]; o[3]++)
|
||||
{
|
||||
i[perm[3]] = o[3];
|
||||
for (o[2] = 0; o[2] < out_shape[2]; o[2]++)
|
||||
{
|
||||
i[perm[2]] = o[2];
|
||||
for (o[1] = 0; o[1] < out_shape[1]; o[1]++)
|
||||
{
|
||||
i[perm[1]] = o[1];
|
||||
for (o[0] = 0; o[0] < out_shape[0]; o[0]++)
|
||||
{
|
||||
i[perm[0]] = o[0];
|
||||
output[offset(out_shape, o)] = input[offset(in_shape, i)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void strided_slice(const T *input, T *output, const runtime_shape_t &in_shape, const runtime_shape_t &begin, const runtime_shape_t &end, const runtime_shape_t &strides)
|
||||
{
|
||||
auto loop_cond = [](int32_t i, int32_t stop, int32_t stride) {
|
||||
return stride > 0 ? i < stop : i > stop;
|
||||
};
|
||||
|
||||
for (int32_t d0 = begin[0]; loop_cond(d0, end[0], strides[0]); d0 += strides[0])
|
||||
{
|
||||
auto d0_origin = input + (size_t)d0 * in_shape[1] * in_shape[2] * in_shape[3];
|
||||
for (int d1 = begin[1]; loop_cond(d1, end[1], strides[1]); d1 += strides[1])
|
||||
{
|
||||
auto d1_origin = d0_origin + (size_t)d1 * in_shape[2] * in_shape[3];
|
||||
for (int32_t d2 = begin[2]; loop_cond(d2, end[2], strides[2]); d2 += strides[2])
|
||||
{
|
||||
auto d2_origin = d1_origin + (size_t)d2 * in_shape[3];
|
||||
for (int32_t d3 = begin[3]; loop_cond(d3, end[3], strides[3]); d3 += strides[3])
|
||||
*output++ = d2_origin[d3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <xtl/xspan.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
class binary_reader
|
||||
{
|
||||
public:
|
||||
binary_reader(std::istream &stream)
|
||||
: stream_(stream)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T read()
|
||||
{
|
||||
T value;
|
||||
read(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void read(T &value)
|
||||
{
|
||||
stream_.read(reinterpret_cast<char *>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void read_array(xtl::span<T> value)
|
||||
{
|
||||
stream_.read(reinterpret_cast<char *>(value.data()), value.size_bytes());
|
||||
}
|
||||
|
||||
std::streampos position() const
|
||||
{
|
||||
return stream_.tellg();
|
||||
}
|
||||
|
||||
void position(std::streampos pos)
|
||||
{
|
||||
stream_.seekg(pos);
|
||||
}
|
||||
|
||||
void skip(std::streamoff off)
|
||||
{
|
||||
stream_.seekg(off, std::ios::cur);
|
||||
}
|
||||
|
||||
size_t avail()
|
||||
{
|
||||
auto pos = stream_.tellg();
|
||||
stream_.seekg(0, std::ios::end);
|
||||
auto end = stream_.tellg();
|
||||
stream_.seekg(pos);
|
||||
return size_t(end - pos);
|
||||
}
|
||||
|
||||
private:
|
||||
std::istream &stream_;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <xtl/xspan.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
class binary_writer
|
||||
{
|
||||
public:
|
||||
binary_writer(std::ostream &stream)
|
||||
: stream_(stream)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write(T &&value)
|
||||
{
|
||||
stream_.write(reinterpret_cast<const char *>(&value), sizeof(value));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void write_array(xtl::span<const T> value)
|
||||
{
|
||||
stream_.write(reinterpret_cast<const char *>(value.data()), value.size_bytes());
|
||||
}
|
||||
|
||||
std::streampos position() const
|
||||
{
|
||||
return stream_.tellp();
|
||||
}
|
||||
|
||||
void position(std::streampos pos)
|
||||
{
|
||||
stream_.seekp(pos);
|
||||
}
|
||||
|
||||
std::streamoff align_position(size_t alignment)
|
||||
{
|
||||
auto pos = position();
|
||||
auto rem = pos % alignment;
|
||||
if (rem != 0)
|
||||
{
|
||||
auto off = std::streamoff(alignment - rem);
|
||||
position(pos + off);
|
||||
return off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream &stream_;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,207 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../node_body.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
struct cpu_conv2d_options
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
int32_t out_channels;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
value_range<float> fused_activation;
|
||||
xtl::span<const float> weights;
|
||||
xtl::span<const float> bias;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(input);
|
||||
reader.read(output);
|
||||
reader.read(in_shape);
|
||||
reader.read(out_channels);
|
||||
reader.read(padding_h);
|
||||
reader.read(padding_w);
|
||||
reader.read(filter_h);
|
||||
reader.read(filter_w);
|
||||
reader.read(stride_h);
|
||||
reader.read(stride_w);
|
||||
reader.read(dilation_h);
|
||||
reader.read(dilation_w);
|
||||
reader.read(fused_activation);
|
||||
reader.read_span(weights, (size_t)out_channels * in_shape[3] * filter_h * filter_w);
|
||||
reader.read_span(bias, out_channels);
|
||||
}
|
||||
};
|
||||
|
||||
struct cpu_depthwise_conv2d_options
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
value_range<float> fused_activation;
|
||||
xtl::span<const float> weights;
|
||||
xtl::span<const float> bias;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(input);
|
||||
reader.read(output);
|
||||
reader.read(in_shape);
|
||||
reader.read(padding_h);
|
||||
reader.read(padding_w);
|
||||
reader.read(filter_h);
|
||||
reader.read(filter_w);
|
||||
reader.read(stride_h);
|
||||
reader.read(stride_w);
|
||||
reader.read(dilation_h);
|
||||
reader.read(dilation_w);
|
||||
reader.read(fused_activation);
|
||||
reader.read_span(weights, (size_t)in_shape[3] * filter_h * filter_w);
|
||||
reader.read_span(bias, in_shape[3]);
|
||||
}
|
||||
};
|
||||
|
||||
struct cpu_reduce_window2d_options : simple_node_body<cpu_reduce_window2d_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
reduce_op_t reduce_op;
|
||||
runtime_shape_t in_shape;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
float init_value;
|
||||
value_range<float> fused_activation;
|
||||
};
|
||||
|
||||
struct cpu_quantized_conv2d_options
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
int32_t out_channels;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
int32_t input_offset;
|
||||
int32_t filter_offset;
|
||||
int32_t output_mul;
|
||||
int32_t output_shift;
|
||||
int32_t output_offset;
|
||||
xtl::span<const uint8_t> weights;
|
||||
xtl::span<const int32_t> bias;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(input);
|
||||
reader.read(output);
|
||||
reader.read(in_shape);
|
||||
reader.read(out_channels);
|
||||
reader.read(padding_h);
|
||||
reader.read(padding_w);
|
||||
reader.read(filter_h);
|
||||
reader.read(filter_w);
|
||||
reader.read(stride_h);
|
||||
reader.read(stride_w);
|
||||
reader.read(dilation_h);
|
||||
reader.read(dilation_w);
|
||||
reader.read(input_offset);
|
||||
reader.read(filter_offset);
|
||||
reader.read(output_mul);
|
||||
reader.read(output_shift);
|
||||
reader.read(output_offset);
|
||||
reader.read_span(weights, (size_t)out_channels * in_shape[3] * filter_h * filter_w);
|
||||
reader.read_span(bias, out_channels);
|
||||
}
|
||||
};
|
||||
|
||||
struct cpu_quantized_depthwise_conv2d_options
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
int32_t input_offset;
|
||||
int32_t filter_offset;
|
||||
int32_t output_mul;
|
||||
int32_t output_shift;
|
||||
int32_t output_offset;
|
||||
xtl::span<const uint8_t> weights;
|
||||
xtl::span<const int32_t> bias;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(input);
|
||||
reader.read(output);
|
||||
reader.read(in_shape);
|
||||
reader.read(padding_h);
|
||||
reader.read(padding_w);
|
||||
reader.read(filter_h);
|
||||
reader.read(filter_w);
|
||||
reader.read(stride_h);
|
||||
reader.read(stride_w);
|
||||
reader.read(dilation_h);
|
||||
reader.read(dilation_w);
|
||||
reader.read(input_offset);
|
||||
reader.read(filter_offset);
|
||||
reader.read(output_mul);
|
||||
reader.read(output_shift);
|
||||
reader.read(output_offset);
|
||||
reader.read_span(weights, (size_t)in_shape[3] * filter_h * filter_w);
|
||||
reader.read_span(bias, in_shape[3]);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "model.h"
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <xtl/xspan.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
class interpreter_base;
|
||||
typedef void (*run_callback_t)(void *userdata);
|
||||
typedef void (*error_callback_t)(const char *err, void *userdata);
|
||||
typedef void (*node_profile_callback_t)(runtime_opcode op, std::chrono::nanoseconds duration, void *userdata);
|
||||
typedef void (interpreter_base::*interpreter_step_t)();
|
||||
|
||||
class interpreter_base
|
||||
{
|
||||
using clock_t = std::chrono::system_clock;
|
||||
|
||||
public:
|
||||
bool try_load_model(const uint8_t *buffer);
|
||||
|
||||
size_t inputs_size() const noexcept { return model_header_->inputs; }
|
||||
size_t outputs_size() const noexcept { return model_header_->outputs; }
|
||||
size_t nodes_size() const noexcept { return model_header_->nodes; }
|
||||
|
||||
const runtime_shape_t &input_shape_at(size_t index) const noexcept { return input_shapes_.at(index); }
|
||||
const memory_range &input_at(size_t index) const noexcept { return inputs_[index]; }
|
||||
const memory_range &output_at(size_t index) const noexcept { return outputs_[index]; }
|
||||
|
||||
template <class T>
|
||||
xtl::span<T> memory_at(const memory_range &range) const noexcept
|
||||
{
|
||||
auto span = memory_at(range);
|
||||
return { reinterpret_cast<T *>(span.data()), span.size() / sizeof(T) };
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds total_duration() const noexcept { return total_duration_; }
|
||||
|
||||
void run(run_callback_t callback, error_callback_t on_error, node_profile_callback_t node_profile, void *userdata);
|
||||
|
||||
protected:
|
||||
virtual bool initialize();
|
||||
virtual xtl::span<uint8_t> memory_at(const memory_range &range) const noexcept;
|
||||
|
||||
private:
|
||||
void step();
|
||||
|
||||
private:
|
||||
const model_header *model_header_;
|
||||
std::unique_ptr<uint8_t[]> main_mem_;
|
||||
xtl::span<const memory_range> inputs_;
|
||||
xtl::span<const memory_range> outputs_;
|
||||
xtl::span<const runtime_shape_t> input_shapes_;
|
||||
xtl::span<const node_header> node_headers_;
|
||||
xtl::span<const uint8_t> constants_;
|
||||
const uint8_t *node_body_start_;
|
||||
error_callback_t on_error_;
|
||||
run_callback_t run_callback_;
|
||||
node_profile_callback_t node_profile_;
|
||||
void *userdata_;
|
||||
size_t cnt_node_;
|
||||
const uint8_t *cnt_node_body_;
|
||||
std::chrono::nanoseconds total_duration_;
|
||||
std::optional<clock_t::time_point> last_time_;
|
||||
runtime_opcode last_op_;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "k210_sim_types.h"
|
||||
#include <runtime/interpreter.h>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace k210
|
||||
{
|
||||
struct k210_interpreter_context
|
||||
{
|
||||
interpreter_base *interpreter;
|
||||
interpreter_step_t step;
|
||||
};
|
||||
|
||||
class interpreter : public interpreter_base
|
||||
{
|
||||
public:
|
||||
using interpreter_base::memory_at;
|
||||
|
||||
interpreter();
|
||||
|
||||
#if !NNCASE_TARGET_K210_SIMULATOR
|
||||
|
||||
dmac_channel_number_t dma_ch() const noexcept { return dma_ch_; }
|
||||
void dma_ch(dmac_channel_number_t dma_ch) noexcept { dma_ch_ = dma_ch; }
|
||||
k210_interpreter_context &context() noexcept { return context_; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
xtl::span<uint8_t> memory_at(const memory_range &range) const noexcept override;
|
||||
|
||||
private:
|
||||
#if NNCASE_TARGET_K210_SIMULATOR
|
||||
std::unique_ptr<uint8_t[]> kpu_mem_;
|
||||
#else
|
||||
dmac_channel_number_t dma_ch_;
|
||||
k210_interpreter_context context_;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../node_body.h"
|
||||
#include "k210_runtime_op_utility.h"
|
||||
#include "k210_sim_types.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace k210
|
||||
{
|
||||
struct kpu_upload_options : simple_node_body<kpu_upload_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
};
|
||||
|
||||
struct kpu_conv2d_options
|
||||
{
|
||||
memory_range main_mem_output;
|
||||
int32_t batches;
|
||||
int32_t reserved0;
|
||||
kpu_layer_argument_t layer;
|
||||
xtl::span<const kpu_batchnorm_argument_t> batch_norm;
|
||||
const kpu_activate_table_t *activation;
|
||||
xtl::span<const uint8_t> weights;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(main_mem_output);
|
||||
reader.read(batches);
|
||||
reader.read(reserved0);
|
||||
reader.read(layer);
|
||||
|
||||
auto ic = layer.image_channel_num.data.i_ch_num + 1;
|
||||
auto oc = layer.image_channel_num.data.o_ch_num + 1;
|
||||
auto filter = get_kpu_filter_size((kpu_filter_type_t)layer.kernel_pool_type_cfg.data.kernel_type);
|
||||
auto weights_size = layer.interrupt_enabe.data.depth_wise_layer
|
||||
? oc * filter * filter
|
||||
: ic * oc * filter * filter;
|
||||
|
||||
reader.skip(layer.kernel_pool_type_cfg.data.bwsx_base_addr);
|
||||
reader.read_span(batch_norm, oc);
|
||||
reader.skip(layer.kernel_calc_type_cfg.data.active_addr);
|
||||
reader.get_ref(activation);
|
||||
reader.skip(layer.kernel_load_cfg.data.para_start_addr);
|
||||
reader.read_span(weights, weights_size);
|
||||
#if !NNCASE_TARGET_K210_SIMULATOR
|
||||
layer.kernel_pool_type_cfg.data.bwsx_base_addr = (uintptr_t)batch_norm.data();
|
||||
layer.kernel_calc_type_cfg.data.active_addr = (uintptr_t)activation;
|
||||
layer.kernel_load_cfg.data.para_start_addr = (uintptr_t)weights.data();
|
||||
#endif
|
||||
}
|
||||
|
||||
void serialize(binary_writer &writer)
|
||||
{
|
||||
writer.write(main_mem_output);
|
||||
writer.write(batches);
|
||||
writer.write(reserved0);
|
||||
|
||||
auto layer_pos = writer.position();
|
||||
writer.position(layer_pos + std::streamoff(sizeof(layer)));
|
||||
layer.kernel_pool_type_cfg.data.bwsx_base_addr = (uint32_t)writer.align_position(8);
|
||||
writer.write_array(batch_norm);
|
||||
layer.kernel_calc_type_cfg.data.active_addr = (uint32_t)writer.align_position(256);
|
||||
writer.write(*activation);
|
||||
layer.kernel_load_cfg.data.para_start_addr = (uint32_t)writer.align_position(128);
|
||||
writer.write_array(weights);
|
||||
|
||||
auto end_pos = writer.position();
|
||||
writer.position(layer_pos);
|
||||
writer.write(layer);
|
||||
writer.position(end_pos);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "k210_sim_types.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace k210
|
||||
{
|
||||
struct kpu_layout
|
||||
{
|
||||
int32_t groups;
|
||||
int32_t row_len;
|
||||
int32_t row_pitch;
|
||||
};
|
||||
|
||||
inline kpu_layout get_kpu_row_layout(int32_t width)
|
||||
{
|
||||
kpu_layout layout;
|
||||
|
||||
if (width <= 16)
|
||||
{
|
||||
layout.groups = 4;
|
||||
layout.row_len = 1;
|
||||
layout.row_pitch = 16;
|
||||
}
|
||||
else if (width <= 32)
|
||||
{
|
||||
layout.groups = 2;
|
||||
layout.row_len = 1;
|
||||
layout.row_pitch = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.groups = 1;
|
||||
layout.row_len = (width + 63) / 64;
|
||||
layout.row_pitch = 64;
|
||||
}
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_filter_size(kpu_filter_type_t filter)
|
||||
{
|
||||
switch (filter)
|
||||
{
|
||||
case kpu_filter_1x1:
|
||||
return 1;
|
||||
case kpu_filter_3x3:
|
||||
return 3;
|
||||
default:
|
||||
NNCASE_THROW(std::runtime_error, "Invalid kpu filter");
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_padding(kpu_filter_type_t filter)
|
||||
{
|
||||
switch (filter)
|
||||
{
|
||||
case kpu_filter_1x1:
|
||||
return 0;
|
||||
case kpu_filter_3x3:
|
||||
return 1;
|
||||
default:
|
||||
NNCASE_THROW(std::runtime_error, "Invalid kpu filter");
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_rows(int32_t width, int32_t height, int32_t channels)
|
||||
{
|
||||
auto layout = get_kpu_row_layout(width);
|
||||
auto one_line_channels = std::min(channels, layout.groups);
|
||||
auto blocks = (channels + one_line_channels - 1) / one_line_channels;
|
||||
auto size = layout.row_len * height * blocks;
|
||||
return size;
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_bytes(int32_t width, int32_t height, int32_t channels)
|
||||
{
|
||||
return get_kpu_rows(width, height, channels) * 64;
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_bytes(const runtime_shape_t &shape)
|
||||
{
|
||||
return get_kpu_bytes(shape[3], shape[2], shape[1]) * shape[0];
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_filter_size(kpu_pool_type_t filter)
|
||||
{
|
||||
switch (filter)
|
||||
{
|
||||
case kpu_pool_bypass:
|
||||
return 1;
|
||||
case kpu_pool_max_2_s2:
|
||||
case kpu_pool_mean_2_s2:
|
||||
case kpu_pool_left_top_2_s2:
|
||||
case kpu_pool_right_top_2_s2:
|
||||
case kpu_pool_max_2_s1:
|
||||
case kpu_pool_mean_2_s1:
|
||||
return 2;
|
||||
case kpu_pool_max_4_s4:
|
||||
case kpu_pool_mean_4_s4:
|
||||
case kpu_pool_left_top_4_s4:
|
||||
return 4;
|
||||
default:
|
||||
NNCASE_THROW(std::runtime_error, "Invalid kpu filter");
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_filter_stride(kpu_pool_type_t filter)
|
||||
{
|
||||
switch (filter)
|
||||
{
|
||||
case kpu_pool_bypass:
|
||||
return 1;
|
||||
case kpu_pool_max_2_s2:
|
||||
case kpu_pool_mean_2_s2:
|
||||
case kpu_pool_left_top_2_s2:
|
||||
case kpu_pool_right_top_2_s2:
|
||||
return 2;
|
||||
case kpu_pool_max_2_s1:
|
||||
case kpu_pool_mean_2_s1:
|
||||
return 1;
|
||||
case kpu_pool_max_4_s4:
|
||||
case kpu_pool_mean_4_s4:
|
||||
case kpu_pool_left_top_4_s4:
|
||||
return 4;
|
||||
default:
|
||||
NNCASE_THROW(std::runtime_error, "Invalid kpu pool type");
|
||||
}
|
||||
}
|
||||
|
||||
inline int32_t get_kpu_pool_output_size(int32_t input, kpu_pool_type_t pool_type)
|
||||
{
|
||||
return input / get_kpu_filter_stride(pool_type);
|
||||
}
|
||||
|
||||
inline std::array<int32_t, 2> get_kpu_select_pool_offset(kpu_pool_type_t pool_type)
|
||||
{
|
||||
switch (pool_type)
|
||||
{
|
||||
case kpu_pool_left_top_2_s2:
|
||||
return { 0, 0 };
|
||||
case kpu_pool_right_top_2_s2:
|
||||
return { 0, 1 };
|
||||
case kpu_pool_left_top_4_s4:
|
||||
return { 0, 0 };
|
||||
default:
|
||||
NNCASE_THROW(std::runtime_error, "Invalid kpu pool type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef __riscv64
|
||||
#define NNCASE_TARGET_K210_SIMULATOR 0
|
||||
#include <kpu.h>
|
||||
#else
|
||||
#define NNCASE_TARGET_K210_SIMULATOR 1
|
||||
#endif
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace k210
|
||||
{
|
||||
#if NNCASE_TARGET_K210_SIMULATOR
|
||||
typedef struct
|
||||
{
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t int_en : 1;
|
||||
uint64_t ram_flag : 1;
|
||||
uint64_t full_add : 1;
|
||||
uint64_t depth_wise_layer : 1;
|
||||
uint64_t reserved : 60;
|
||||
} data;
|
||||
} interrupt_enabe;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t image_src_addr : 15;
|
||||
uint64_t reserved0 : 17;
|
||||
uint64_t image_dst_addr : 15;
|
||||
uint64_t reserved1 : 17;
|
||||
} data;
|
||||
} image_addr;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t i_ch_num : 10;
|
||||
uint64_t reserved0 : 22;
|
||||
uint64_t o_ch_num : 10;
|
||||
uint64_t reserved1 : 6;
|
||||
uint64_t o_ch_num_coef : 10;
|
||||
uint64_t reserved2 : 6;
|
||||
} data;
|
||||
} image_channel_num;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t i_row_wid : 10;
|
||||
uint64_t i_col_high : 9;
|
||||
uint64_t reserved0 : 13;
|
||||
uint64_t o_row_wid : 10;
|
||||
uint64_t o_col_high : 9;
|
||||
uint64_t reserved1 : 13;
|
||||
} data;
|
||||
} image_size;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t kernel_type : 3;
|
||||
uint64_t pad_type : 1;
|
||||
uint64_t pool_type : 4;
|
||||
uint64_t first_stride : 1;
|
||||
uint64_t bypass_conv : 1;
|
||||
uint64_t load_para : 1;
|
||||
uint64_t reserved0 : 5;
|
||||
uint64_t dma_burst_size : 8;
|
||||
uint64_t pad_value : 8;
|
||||
uint64_t bwsx_base_addr : 32;
|
||||
} data;
|
||||
} kernel_pool_type_cfg;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t load_coor : 1;
|
||||
uint64_t load_time : 6;
|
||||
uint64_t reserved0 : 8;
|
||||
uint64_t para_size : 17;
|
||||
uint64_t para_start_addr : 32;
|
||||
} data;
|
||||
} kernel_load_cfg;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t coef_column_offset : 4;
|
||||
uint64_t coef_row_offset : 12;
|
||||
uint64_t reserved0 : 48;
|
||||
} data;
|
||||
} kernel_offset;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t channel_switch_addr : 15;
|
||||
uint64_t reserved : 1;
|
||||
uint64_t row_switch_addr : 4;
|
||||
uint64_t coef_size : 8;
|
||||
uint64_t coef_group : 3;
|
||||
uint64_t load_act : 1;
|
||||
uint64_t active_addr : 32;
|
||||
} data;
|
||||
} kernel_calc_type_cfg;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t wb_channel_switch_addr : 15;
|
||||
uint64_t reserved0 : 1;
|
||||
uint64_t wb_row_switch_addr : 4;
|
||||
uint64_t wb_group : 3;
|
||||
uint64_t reserved1 : 41;
|
||||
} data;
|
||||
} write_back_cfg;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t shr_w : 4;
|
||||
uint64_t shr_x : 4;
|
||||
uint64_t arg_w : 24;
|
||||
uint64_t arg_x : 24;
|
||||
uint64_t reserved0 : 8;
|
||||
} data;
|
||||
} conv_value;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t arg_add : 40;
|
||||
uint64_t reserved : 24;
|
||||
} data;
|
||||
} conv_value2;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t send_data_out : 1;
|
||||
uint64_t reserved : 15;
|
||||
uint64_t channel_byte_num : 16;
|
||||
uint64_t dma_total_byte : 32;
|
||||
} data;
|
||||
} dma_parameter;
|
||||
} kpu_layer_argument_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t shift_number : 8;
|
||||
uint64_t y_mul : 16;
|
||||
uint64_t x_start : 36;
|
||||
} data;
|
||||
} activate_para[16];
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint8_t result_bias[8];
|
||||
} data;
|
||||
} activate_para_bias0;
|
||||
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint8_t result_bias[8];
|
||||
} data;
|
||||
} activate_para_bias1;
|
||||
} kpu_activate_table_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union {
|
||||
uint64_t reg;
|
||||
struct
|
||||
{
|
||||
uint64_t norm_mul : 24;
|
||||
uint64_t norm_add : 32;
|
||||
uint64_t norm_shift : 4;
|
||||
} data;
|
||||
} batchnorm;
|
||||
} kpu_batchnorm_argument_t;
|
||||
|
||||
typedef enum _kpu_filter_type
|
||||
{
|
||||
kpu_filter_1x1 = 0,
|
||||
kpu_filter_3x3 = 1
|
||||
} kpu_filter_type_t;
|
||||
|
||||
typedef enum _kpu_pool_type
|
||||
{
|
||||
kpu_pool_bypass = 0,
|
||||
kpu_pool_max_2_s2 = 1,
|
||||
kpu_pool_mean_2_s2 = 2,
|
||||
kpu_pool_max_4_s4 = 3,
|
||||
kpu_pool_mean_4_s4 = 4,
|
||||
kpu_pool_left_top_2_s2 = 5,
|
||||
kpu_pool_right_top_2_s2 = 6,
|
||||
kpu_pool_left_top_4_s4 = 7,
|
||||
kpu_pool_mean_2_s1 = 8,
|
||||
kpu_pool_max_2_s1 = 9
|
||||
} kpu_pool_type_t;
|
||||
|
||||
struct kpu_batchnorm_segment
|
||||
{
|
||||
int32_t mul;
|
||||
int32_t shift;
|
||||
int32_t add;
|
||||
};
|
||||
|
||||
struct kpu_activation_segment
|
||||
{
|
||||
int64_t start_x;
|
||||
int32_t mul;
|
||||
int32_t shift;
|
||||
int32_t add;
|
||||
};
|
||||
|
||||
using kpu_activation_table_t = std::array<kpu_activation_segment, 16>;
|
||||
|
||||
struct piecewise_linear_segment
|
||||
{
|
||||
float start;
|
||||
float mul;
|
||||
float add;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../datatypes.h"
|
||||
#include "runtime_op.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
enum model_target : uint32_t
|
||||
{
|
||||
MODEL_TARGET_CPU = 0,
|
||||
MODEL_TARGET_K210 = 1
|
||||
};
|
||||
|
||||
struct model_header
|
||||
{
|
||||
uint32_t identifier;
|
||||
uint32_t version;
|
||||
uint32_t flags;
|
||||
model_target target;
|
||||
uint32_t constants;
|
||||
uint32_t main_mem;
|
||||
uint32_t nodes;
|
||||
uint32_t inputs;
|
||||
uint32_t outputs;
|
||||
uint32_t reserved0;
|
||||
};
|
||||
|
||||
constexpr uint32_t MODEL_IDENTIFIER = 'KMDL';
|
||||
constexpr uint32_t MODEL_VERSION = 4;
|
||||
|
||||
struct node_header
|
||||
{
|
||||
runtime_opcode opcode;
|
||||
uint32_t body_size;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../node_body.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace neutral
|
||||
{
|
||||
struct binary_options : public simple_node_body<binary_options>
|
||||
{
|
||||
memory_range input_a;
|
||||
memory_range input_b;
|
||||
memory_range output;
|
||||
binary_op_t binary_op;
|
||||
runtime_shape_t in_a_shape;
|
||||
runtime_shape_t in_b_shape;
|
||||
runtime_shape_t out_shape;
|
||||
value_range<float> fused_activation;
|
||||
};
|
||||
|
||||
struct concat_options
|
||||
{
|
||||
memory_range output;
|
||||
uint32_t inner_size;
|
||||
uint32_t outer_size;
|
||||
uint32_t inputs_count;
|
||||
xtl::span<const memory_range> inputs;
|
||||
xtl::span<const int32_t> dims;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(output);
|
||||
reader.read(inner_size);
|
||||
reader.read(outer_size);
|
||||
reader.read(inputs_count);
|
||||
reader.read_span(inputs, inputs_count);
|
||||
reader.read_span(dims, inputs_count);
|
||||
}
|
||||
|
||||
void serialize(binary_writer &writer) const
|
||||
{
|
||||
writer.write(output);
|
||||
writer.write(inner_size);
|
||||
writer.write(outer_size);
|
||||
writer.write(inputs_count);
|
||||
writer.write_array(inputs);
|
||||
writer.write_array(dims);
|
||||
}
|
||||
};
|
||||
|
||||
struct conv2d_options
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
int32_t groups;
|
||||
int32_t out_channels;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
value_range<float> fused_activation;
|
||||
xtl::span<const float> weights;
|
||||
xtl::span<const float> bias;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(input);
|
||||
reader.read(output);
|
||||
reader.read(in_shape);
|
||||
reader.read(groups);
|
||||
reader.read(out_channels);
|
||||
reader.read(padding_h);
|
||||
reader.read(padding_w);
|
||||
reader.read(filter_h);
|
||||
reader.read(filter_w);
|
||||
reader.read(stride_h);
|
||||
reader.read(stride_w);
|
||||
reader.read(dilation_h);
|
||||
reader.read(dilation_w);
|
||||
reader.read(fused_activation);
|
||||
reader.read_span(weights, (size_t)out_channels * in_shape[1] / groups * filter_h * filter_w);
|
||||
reader.read_span(bias, out_channels);
|
||||
}
|
||||
|
||||
void serialize(binary_writer &writer) const
|
||||
{
|
||||
writer.write(input);
|
||||
writer.write(output);
|
||||
writer.write(in_shape);
|
||||
writer.write(groups);
|
||||
writer.write(out_channels);
|
||||
writer.write(padding_h);
|
||||
writer.write(padding_w);
|
||||
writer.write(filter_h);
|
||||
writer.write(filter_w);
|
||||
writer.write(stride_h);
|
||||
writer.write(stride_w);
|
||||
writer.write(dilation_h);
|
||||
writer.write(dilation_w);
|
||||
writer.write(fused_activation);
|
||||
writer.write_array(weights);
|
||||
writer.write_array(bias);
|
||||
}
|
||||
};
|
||||
|
||||
struct dequantize_options : public simple_node_body<dequantize_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
quant_param_t quant_param;
|
||||
};
|
||||
|
||||
struct matmul_options
|
||||
{
|
||||
memory_range input_a;
|
||||
memory_range input_b;
|
||||
memory_range output;
|
||||
int32_t a_rows;
|
||||
int32_t a_cols;
|
||||
int32_t b_cols;
|
||||
value_range<float> fused_activation;
|
||||
xtl::span<const float> bias;
|
||||
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(input_a);
|
||||
reader.read(input_b);
|
||||
reader.read(output);
|
||||
reader.read(a_rows);
|
||||
reader.read(a_cols);
|
||||
reader.read(b_cols);
|
||||
reader.read(fused_activation);
|
||||
reader.read_span(bias, b_cols);
|
||||
}
|
||||
|
||||
void serialize(binary_writer &writer) const
|
||||
{
|
||||
writer.write(input_a);
|
||||
writer.write(input_b);
|
||||
writer.write(output);
|
||||
writer.write(a_rows);
|
||||
writer.write(a_cols);
|
||||
writer.write(b_cols);
|
||||
writer.write(fused_activation);
|
||||
writer.write_array(bias);
|
||||
}
|
||||
};
|
||||
|
||||
struct memory_copy_options : public simple_node_body<memory_copy_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
};
|
||||
|
||||
struct pad_options : public simple_node_body<pad_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
runtime_paddings_t paddings;
|
||||
scalar pad_value;
|
||||
};
|
||||
|
||||
struct quantize_options : public simple_node_body<quantize_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
quant_param_t quant_param;
|
||||
};
|
||||
|
||||
struct reduce_options : public simple_node_body<reduce_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
reduce_op_t reduce_op;
|
||||
runtime_shape_t in_shape;
|
||||
runtime_shape_t out_shape;
|
||||
float init_value;
|
||||
};
|
||||
|
||||
struct reduce_window2d_options : simple_node_body<reduce_window2d_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
reduce_op_t reduce_op;
|
||||
runtime_shape_t in_shape;
|
||||
padding padding_h;
|
||||
padding padding_w;
|
||||
int32_t filter_h;
|
||||
int32_t filter_w;
|
||||
int32_t stride_h;
|
||||
int32_t stride_w;
|
||||
int32_t dilation_h;
|
||||
int32_t dilation_w;
|
||||
float init_value;
|
||||
value_range<float> fused_activation;
|
||||
};
|
||||
|
||||
struct resize_image_options : public simple_node_body<resize_image_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
int32_t out_h;
|
||||
int32_t out_w;
|
||||
image_resize_mode_t mode;
|
||||
bool align_corners;
|
||||
};
|
||||
|
||||
struct softmax_options : public simple_node_body<softmax_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
int32_t inner_size;
|
||||
int32_t outer_size;
|
||||
float beta;
|
||||
};
|
||||
|
||||
struct transpose_options : public simple_node_body<transpose_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
runtime_shape_t perm;
|
||||
};
|
||||
|
||||
struct strided_slice_options : public simple_node_body<strided_slice_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
runtime_shape_t in_shape;
|
||||
runtime_shape_t begin;
|
||||
runtime_shape_t end;
|
||||
runtime_shape_t strides;
|
||||
int32_t begin_mask;
|
||||
int32_t end_mask;
|
||||
int32_t ellipsis_mask;
|
||||
int32_t new_axis_mask;
|
||||
int32_t shrink_axis_mask;
|
||||
};
|
||||
|
||||
struct unary_options : public simple_node_body<unary_options>
|
||||
{
|
||||
memory_range input;
|
||||
memory_range output;
|
||||
unary_op_t unary_op;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../datatypes.h"
|
||||
#include "binary_writer.h"
|
||||
#include "span_reader.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
template <class T>
|
||||
struct simple_node_body
|
||||
{
|
||||
void deserialize(span_reader &reader)
|
||||
{
|
||||
reader.read(static_cast<T &>(*this));
|
||||
}
|
||||
|
||||
void serialize(binary_writer &writer) const
|
||||
{
|
||||
writer.write(static_cast<const T &>(*this));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
BEGINE_DEFINE_TARGET(neutral)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(binary, Binary, 0x0)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(concat, Concat, 0x1)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(conv2d, Conv2D, 0x2)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(dequantize, Dequantize, 0x3)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(matmul, MatMul, 0x4)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(pad, Pad, 0x5)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(quantize, Quantize, 0x6)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(reduce, Reduce, 0x7)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(reduce_window2d, ReduceWindow2D, 0x8)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(memory_copy, MemoryCopy, 0x9)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(resize_image, ResizeImage, 0x0A)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(softmax, Softmax, 0x0B)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(transpose, Transpose, 0x0C)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(strided_slice, StridedSlice, 0x0D)
|
||||
DEFINE_NEUTRAL_RUNTIME_OP(unary, Unary, 0x0E)
|
||||
END_DEFINE_TARGET()
|
||||
|
||||
// CPU
|
||||
BEGINE_DEFINE_TARGET(cpu)
|
||||
DEFINE_RUNTIME_OP(cpu, cpu_conv2d, CPUConv2D, 0x1001)
|
||||
DEFINE_RUNTIME_OP(cpu, cpu_depthwise_conv2d, CPUDepthwiseConv2D, 0x1002)
|
||||
DEFINE_RUNTIME_OP(cpu, cpu_reduce_window2d, CPUReduceWindow2D, 0x1003)
|
||||
DEFINE_RUNTIME_OP(cpu, cpu_quantized_conv2d, CPUQuantizedConv2D, 0x1004)
|
||||
DEFINE_RUNTIME_OP(cpu, cpu_quantized_depthwise_conv2d, CPUQuantizedDepthwiseConv2D, 0x1005)
|
||||
END_DEFINE_TARGET()
|
||||
|
||||
// K210
|
||||
BEGINE_DEFINE_TARGET(k210)
|
||||
DEFINE_RUNTIME_OP(k210, kpu_upload, KPUUpload, 0x2001)
|
||||
DEFINE_RUNTIME_OP(k210, kpu_conv2d, KPUConv2D, 0x2002)
|
||||
END_DEFINE_TARGET()
|
|
@ -1,57 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../datatypes.h"
|
||||
#include <string_view>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
#define BEGINE_DEFINE_TARGET(...)
|
||||
#define DEFINE_NEUTRAL_RUNTIME_OP(id, name, value) rop_##id = value,
|
||||
#define DEFINE_RUNTIME_OP(target, id, name, value) rop_##target##_##id = value,
|
||||
#define END_DEFINE_TARGET()
|
||||
|
||||
enum runtime_opcode : uint32_t
|
||||
{
|
||||
#include "runtime_op.def"
|
||||
};
|
||||
|
||||
#undef DEFINE_NEUTRAL_RUNTIME_OP
|
||||
#undef DEFINE_RUNTIME_OP
|
||||
#define DEFINE_NEUTRAL_RUNTIME_OP(id, name, value) \
|
||||
case rop_##id: \
|
||||
return #name;
|
||||
#define DEFINE_RUNTIME_OP(target, id, name, value) \
|
||||
case rop_##target##_##id: \
|
||||
return #name;
|
||||
|
||||
constexpr std::string_view node_opcode_names(runtime_opcode opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
#include "runtime_op.def"
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
#undef BEGINE_DEFINE_TARGET
|
||||
#undef DEFINE_NEUTRAL_RUNTIME_OP
|
||||
#undef DEFINE_RUNTIME_OP
|
||||
#undef END_DEFINE_TARGET
|
||||
}
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../datatypes.h"
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
inline size_t get_bytes(datatype_t type)
|
||||
{
|
||||
size_t element_size;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case dt_float32:
|
||||
element_size = 4;
|
||||
break;
|
||||
case dt_uint8:
|
||||
element_size = 1;
|
||||
break;
|
||||
default:
|
||||
NNCASE_THROW(std::runtime_error, "Not supported data type");
|
||||
}
|
||||
|
||||
return element_size;
|
||||
}
|
||||
|
||||
template <int32_t Bits, class T>
|
||||
uint8_t count_leading_zeros(T value)
|
||||
{
|
||||
uint8_t num_zeroes = 0;
|
||||
for (int32_t i = Bits - 1; i >= 0; i--)
|
||||
{
|
||||
if ((value & (1ULL << i)) == 0)
|
||||
++num_zeroes;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return num_zeroes;
|
||||
}
|
||||
|
||||
template <class T = uint64_t>
|
||||
inline T bit_mask(uint8_t shift)
|
||||
{
|
||||
return (T(1) << shift) - 1;
|
||||
}
|
||||
|
||||
template <class T, bool Banker = false>
|
||||
T carry_shift(T value, uint8_t shift)
|
||||
{
|
||||
if (shift > 0)
|
||||
{
|
||||
if constexpr (Banker)
|
||||
{
|
||||
T result;
|
||||
// Sign | Int (T - shift - 1 bits) | Frac (shift bits)
|
||||
// S IIII FFF
|
||||
auto integral = value >> shift;
|
||||
auto fractional = value & bit_mask(shift);
|
||||
auto sign = value < 0 ? -1 : 1;
|
||||
auto half = 1 << (shift - 1);
|
||||
|
||||
// frac < 0.5
|
||||
if (fractional < half)
|
||||
{
|
||||
return integral;
|
||||
}
|
||||
// frac > 0.5
|
||||
else if (fractional > half)
|
||||
{
|
||||
return integral + sign;
|
||||
}
|
||||
// frac == 0.5
|
||||
else
|
||||
{
|
||||
// odd
|
||||
if (integral & 1)
|
||||
return integral + sign;
|
||||
// even
|
||||
else
|
||||
return integral;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
value >>= shift - 1;
|
||||
if (value & 0x1)
|
||||
{
|
||||
if (value < 0)
|
||||
value = (value >> 1) - 1;
|
||||
else
|
||||
value = (value >> 1) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <bool Banker = false>
|
||||
inline int32_t mul_and_carry_shift(int32_t value, int32_t mul, uint8_t shift)
|
||||
{
|
||||
return (int32_t)carry_shift<int64_t, Banker>((int64_t)value * mul, shift);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct to_datatype
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_datatype<float>
|
||||
{
|
||||
static constexpr datatype_t type = dt_float32;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct to_datatype<uint8_t>
|
||||
{
|
||||
static constexpr datatype_t type = dt_uint8;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline constexpr datatype_t to_datatype_v = to_datatype<T>::type;
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <xtl/xspan.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
class span_reader
|
||||
{
|
||||
public:
|
||||
span_reader(xtl::span<const uint8_t> span)
|
||||
: span_(span)
|
||||
{
|
||||
}
|
||||
|
||||
bool empty() const noexcept { return span_.empty(); }
|
||||
|
||||
template <class T>
|
||||
T read()
|
||||
{
|
||||
auto value = *reinterpret_cast<const T *>(span_.data());
|
||||
advance(sizeof(T));
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void read(T &value)
|
||||
{
|
||||
value = *reinterpret_cast<const T *>(span_.data());
|
||||
advance(sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void read_span(xtl::span<const T> &span, size_t size)
|
||||
{
|
||||
span = { reinterpret_cast<const T *>(span_.data()), size };
|
||||
advance(sizeof(T) * size);
|
||||
}
|
||||
|
||||
template <class T, ptrdiff_t N>
|
||||
void read_span(xtl::span<const T, N> &span)
|
||||
{
|
||||
span = { reinterpret_cast<const T *>(span_.data()), N };
|
||||
advance(sizeof(T) * N);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T *peek() const noexcept
|
||||
{
|
||||
return reinterpret_cast<const T *>(span_.data());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void get_array(const T *&value, size_t size)
|
||||
{
|
||||
value = peek<T>();
|
||||
advance(size * sizeof(T));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void get_ref(const T *&value)
|
||||
{
|
||||
value = peek<T>();
|
||||
advance(sizeof(T));
|
||||
}
|
||||
|
||||
void skip(size_t count)
|
||||
{
|
||||
advance(count);
|
||||
}
|
||||
|
||||
private:
|
||||
void advance(size_t count)
|
||||
{
|
||||
span_ = span_.subspan(count);
|
||||
}
|
||||
|
||||
private:
|
||||
xtl::span<const uint8_t> span_;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
|
||||
// clang-format off
|
||||
#define NNCASE_STRINGFY(x) #x
|
||||
#define NNCASE_CONCAT_2(a, b) a/b
|
||||
#define NNCASE_CONCAT_3(a, b, c) NNCASE_CONCAT_2(NNCASE_CONCAT_2(a, b), c)
|
||||
// clang-format on
|
||||
|
||||
#define NNCASE_TARGET_HEADER_(prefix, target, name) <NNCASE_CONCAT_3(prefix, target, name)>
|
||||
#define NNCASE_TARGET_HEADER(prefix, name) NNCASE_TARGET_HEADER_(prefix, NNCASE_TARGET, name)
|
||||
|
||||
#ifndef NNCASE_NO_EXCEPTIONS
|
||||
#include <stdexcept>
|
||||
#define NNCASE_THROW(exception, ...) throw exception(__VA_ARGS__)
|
||||
#else
|
||||
#define NNCASE_THROW(exception, ...) assert(0 && #exception)
|
||||
#endif
|
|
@ -1,37 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <ir/quantizer.h>
|
||||
#include <memory>
|
||||
#include <scheduler/memory_allocator.h>
|
||||
#include <transforms/transform.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
class target
|
||||
{
|
||||
public:
|
||||
virtual void fill_allocators(std::unordered_map<memory_type_t, scheduler::memory_allocator *> &allocators, std::vector<std::unique_ptr<scheduler::memory_allocator>> &allocator_holders) = 0;
|
||||
virtual void registry_codegen_ops() = 0;
|
||||
virtual void registry_evaluator_ops() = 0;
|
||||
virtual void add_default_transforms(std::vector<std::unique_ptr<transforms::transform>> &transforms) = 0;
|
||||
virtual void add_optimize1_transforms(std::vector<std::unique_ptr<transforms::transform>> &transforms) = 0;
|
||||
virtual void add_optimize2_transforms(std::vector<std::unique_ptr<transforms::transform>> &transforms) = 0;
|
||||
virtual void add_quantization_checkpoint_transforms(std::vector<std::unique_ptr<transforms::transform>> &transforms) = 0;
|
||||
virtual void add_quantization_transforms(ir::quantizer& quantizer, const quant_param_t& input_quant_param, std::vector<std::unique_ptr<transforms::transform>> &transforms) = 0;
|
||||
};
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <nncase.h>
|
||||
#include <kernels/k210/k210_kernels.h>
|
||||
#include <runtime/target_interpreter.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
|
||||
#define NNCASE_DEBUG 0
|
||||
|
||||
namespace
|
||||
{
|
||||
void kpu_upload_dma(dmac_channel_number_t dma_ch, const uint8_t *src, uint8_t *dest, size_t input_size, plic_irq_callback_t callback, void *userdata)
|
||||
{
|
||||
dmac_set_irq(dma_ch, callback, userdata, 1);
|
||||
dmac_set_single_mode(dma_ch, (void *)src, (void *)dest, DMAC_ADDR_INCREMENT, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_16, DMAC_TRANS_WIDTH_64, input_size / 8);
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
class nncase_context
|
||||
{
|
||||
public:
|
||||
int load_kmodel(const uint8_t *buffer)
|
||||
{
|
||||
return interpreter_.try_load_model(buffer) ? 0 : -1;
|
||||
}
|
||||
|
||||
int get_output(uint32_t index, uint8_t **data, size_t *size)
|
||||
{
|
||||
if (index >= interpreter_.outputs_size())
|
||||
return -1;
|
||||
|
||||
auto mem = interpreter_.memory_at<uint8_t>(interpreter_.output_at(index));
|
||||
*data = mem.data();
|
||||
*size = mem.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int run_kmodel(const uint8_t *src, dmac_channel_number_t dma_ch, kpu_done_callback_t done_callback, void *userdata)
|
||||
{
|
||||
done_callback_ = done_callback;
|
||||
userdata_ = userdata;
|
||||
interpreter_.dma_ch(dma_ch);
|
||||
|
||||
auto input = interpreter_.input_at(0);
|
||||
auto mem = interpreter_.memory_at<uint8_t>(input);
|
||||
if (input.memory_type == mem_main)
|
||||
{
|
||||
std::copy(src, src + mem.size(), mem.begin());
|
||||
interpreter_.run(done_thunk, on_error_thunk, node_profile_thunk, this);
|
||||
return 0;
|
||||
}
|
||||
else if (input.memory_type == mem_k210_kpu)
|
||||
{
|
||||
auto shape = interpreter_.input_shape_at(0);
|
||||
if (shape[3] % 64 == 0)
|
||||
{
|
||||
kpu_upload_dma(dma_ch, src, mem.data(), mem.size(), upload_done_thunk, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
kernels::k210::kpu_upload(src, mem.data(), shape);
|
||||
on_upload_done();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
void on_done()
|
||||
{
|
||||
#if NNCASE_DEBUG
|
||||
printf("Total: %fms\n", interpreter_.total_duration().count() / 1e6);
|
||||
#endif
|
||||
|
||||
if (done_callback_)
|
||||
done_callback_(userdata_);
|
||||
}
|
||||
|
||||
void on_upload_done()
|
||||
{
|
||||
interpreter_.run(done_thunk, on_error_thunk, node_profile_thunk, this);
|
||||
}
|
||||
|
||||
static void done_thunk(void *userdata)
|
||||
{
|
||||
reinterpret_cast<nncase_context *>(userdata)->on_done();
|
||||
}
|
||||
|
||||
static void on_error_thunk(const char *err, void *userdata)
|
||||
{
|
||||
#if NNCASE_DEBUG
|
||||
printf("Fatal: %s\n", err);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void node_profile_thunk(runtime_opcode op, std::chrono::nanoseconds duration, void *userdata)
|
||||
{
|
||||
#if NNCASE_DEBUG
|
||||
printf("%s: %fms\n", node_opcode_names(op).data(), duration.count() / 1e6);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int upload_done_thunk(void *userdata)
|
||||
{
|
||||
reinterpret_cast<nncase_context *>(userdata)->on_upload_done();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
interpreter_t interpreter_;
|
||||
kpu_done_callback_t done_callback_;
|
||||
void *userdata_;
|
||||
};
|
||||
|
||||
int nncase_load_kmodel(kpu_model_context_t *ctx, const uint8_t *buffer)
|
||||
{
|
||||
auto nnctx = new (std::nothrow) nncase_context();
|
||||
if (ctx)
|
||||
{
|
||||
ctx->is_nncase = 1;
|
||||
ctx->nncase_ctx = nnctx;
|
||||
return nnctx->load_kmodel(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int nncase_get_output(kpu_model_context_t *ctx, uint32_t index, uint8_t **data, size_t *size)
|
||||
{
|
||||
auto nnctx = reinterpret_cast<nncase_context *>(ctx->nncase_ctx);
|
||||
return nnctx->get_output(index, data, size);
|
||||
}
|
||||
|
||||
void nncase_model_free(kpu_model_context_t *ctx)
|
||||
{
|
||||
auto nnctx = reinterpret_cast<nncase_context *>(ctx->nncase_ctx);
|
||||
delete nnctx;
|
||||
ctx->nncase_ctx = nullptr;
|
||||
}
|
||||
|
||||
int nncase_run_kmodel(kpu_model_context_t *ctx, const uint8_t *src, dmac_channel_number_t dma_ch, kpu_done_callback_t done_callback, void *userdata)
|
||||
{
|
||||
auto nnctx = reinterpret_cast<nncase_context *>(ctx->nncase_ctx);
|
||||
return nnctx->run_kmodel(src, dma_ch, done_callback, userdata);
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <kernels/cpu/cpu_kernels.h>
|
||||
#include <runtime/kernel_registry.h>
|
||||
#include <runtime/cpu/cpu_ops_body.h>
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
kernel_call_result cpu_conv2d(cpu_conv2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
kernels::cpu::conv2d(input.data(), output.data(), options.weights.data(), options.bias.data(), options.in_shape, options.out_channels, options.filter_h,
|
||||
options.filter_w, options.stride_h, options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w, options.fused_activation);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result cpu_depthwise_conv2d(cpu_depthwise_conv2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
kernels::cpu::depthwise_conv2d(input.data(), output.data(), options.weights.data(), options.bias.data(), options.in_shape, options.filter_h,
|
||||
options.filter_w, options.stride_h, options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w, options.fused_activation);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
runtime::kernel_call_result cpu_reduce_window2d(cpu_reduce_window2d_options &options, interpreter_t &interpreter, runtime::interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
auto reduce = [&](auto binary_op, auto window_op) {
|
||||
kernels::cpu::reduce_window2d(input.data(), output.data(), options.init_value, options.in_shape, options.filter_h, options.filter_w, options.stride_h,
|
||||
options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w, options.fused_activation, binary_op, window_op);
|
||||
};
|
||||
|
||||
switch (options.reduce_op)
|
||||
{
|
||||
case reduce_mean:
|
||||
reduce([](auto a, auto b) { return a + b; }, [](auto v, auto k) { return v / k; });
|
||||
return runtime::kcr_done;
|
||||
case reduce_min:
|
||||
reduce([](auto a, auto b) { return std::min(a, b); }, [](auto v, auto k) { return v; });
|
||||
return runtime::kcr_done;
|
||||
case reduce_max:
|
||||
reduce([](auto a, auto b) { return std::max(a, b); }, [](auto v, auto k) { return v; });
|
||||
return kcr_done;
|
||||
default:
|
||||
return kcr_error;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_call_result cpu_quantized_conv2d(cpu_quantized_conv2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
kernels::cpu::quantized_conv2d(input.data(), output.data(), options.weights.data(), options.bias.data(), options.in_shape, options.out_channels, options.filter_h,
|
||||
options.filter_w, options.stride_h, options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w,
|
||||
options.input_offset, options.filter_offset, options.output_mul, options.output_shift, options.output_offset);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result cpu_quantized_depthwise_conv2d(cpu_quantized_depthwise_conv2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
kernels::cpu::quantized_depthwise_conv2d(input.data(), output.data(), options.weights.data(), options.bias.data(), options.in_shape, options.filter_h,
|
||||
options.filter_w, options.stride_h, options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w,
|
||||
options.input_offset, options.filter_offset, options.output_mul, options.output_shift, options.output_offset);
|
||||
return kcr_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <runtime/interpreter.h>
|
||||
#include <runtime/kernel_registry.h>
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
|
||||
bool interpreter_base::try_load_model(const uint8_t *buffer)
|
||||
{
|
||||
auto offset = buffer;
|
||||
model_header_ = reinterpret_cast<const model_header *>(buffer);
|
||||
|
||||
// Validate model
|
||||
if (model_header_->identifier != MODEL_IDENTIFIER || model_header_->version != MODEL_VERSION || (model_header_->target != MODEL_TARGET_CPU && model_header_->target != MODEL_TARGET_K210))
|
||||
return false;
|
||||
|
||||
// Allocate buffers
|
||||
main_mem_.reset(new (std::nothrow) uint8_t[model_header_->main_mem]);
|
||||
if (!main_mem_)
|
||||
return false;
|
||||
|
||||
offset += sizeof(model_header);
|
||||
inputs_ = { reinterpret_cast<const memory_range *>(offset), inputs_size() };
|
||||
offset += sizeof(memory_range) * inputs_size();
|
||||
input_shapes_ = { reinterpret_cast<const runtime_shape_t *>(offset), inputs_size() };
|
||||
offset += sizeof(runtime_shape_t) * inputs_size();
|
||||
outputs_ = { reinterpret_cast<const memory_range *>(offset), outputs_size() };
|
||||
offset += sizeof(memory_range) * outputs_size();
|
||||
constants_ = { offset, model_header_->constants };
|
||||
offset += constants_.size();
|
||||
node_headers_ = { reinterpret_cast<const node_header *>(offset), nodes_size() };
|
||||
offset += sizeof(node_header) * nodes_size();
|
||||
node_body_start_ = offset;
|
||||
|
||||
return initialize();
|
||||
}
|
||||
|
||||
bool interpreter_base::initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void interpreter_base::run(run_callback_t callback, error_callback_t on_error, node_profile_callback_t node_profile, void *userdata)
|
||||
{
|
||||
run_callback_ = callback;
|
||||
on_error_ = on_error;
|
||||
node_profile_ = node_profile;
|
||||
userdata_ = userdata;
|
||||
cnt_node_ = 0;
|
||||
cnt_node_body_ = node_body_start_;
|
||||
total_duration_ = {};
|
||||
last_time_.reset();
|
||||
step();
|
||||
}
|
||||
|
||||
void interpreter_base::step()
|
||||
{
|
||||
auto result = kcr_done;
|
||||
|
||||
while (result == kcr_done)
|
||||
{
|
||||
if (!last_time_)
|
||||
{
|
||||
last_time_ = clock_t::now();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto now = clock_t::now();
|
||||
auto duration = now - *last_time_;
|
||||
total_duration_ += duration;
|
||||
last_time_ = now;
|
||||
|
||||
if (node_profile_)
|
||||
node_profile_(last_op_, duration, userdata_);
|
||||
}
|
||||
|
||||
if (cnt_node_ == nodes_size())
|
||||
{
|
||||
run_callback_(userdata_);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto node_id = cnt_node_++;
|
||||
auto header = node_headers_[node_id];
|
||||
xtl::span<const uint8_t> body(cnt_node_body_, header.body_size);
|
||||
cnt_node_body_ += header.body_size;
|
||||
last_op_ = header.opcode;
|
||||
|
||||
result = call_kernel(header.opcode, body, static_cast<interpreter_t &>(*this), &interpreter_base::step);
|
||||
|
||||
if (result == kcr_error)
|
||||
{
|
||||
if (on_error_)
|
||||
{
|
||||
char buffer[256];
|
||||
auto name = node_opcode_names(header.opcode);
|
||||
if (!name.empty())
|
||||
std::sprintf(buffer, "error occurs in running kernel: %s", name.data());
|
||||
else
|
||||
std::sprintf(buffer, "Unknown opcode: (%d)", header.opcode);
|
||||
on_error_(buffer, userdata_);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xtl::span<uint8_t> interpreter_base::memory_at(const memory_range &range) const noexcept
|
||||
{
|
||||
uintptr_t base;
|
||||
|
||||
switch (range.memory_type)
|
||||
{
|
||||
case mem_const:
|
||||
base = (uintptr_t)constants_.data();
|
||||
break;
|
||||
case mem_main:
|
||||
base = (uintptr_t)main_mem_.get();
|
||||
break;
|
||||
default:
|
||||
base = 0;
|
||||
assert(!"Invalid memory type");
|
||||
break;
|
||||
}
|
||||
|
||||
return { reinterpret_cast<uint8_t *>(base + range.start), range.size };
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <runtime/k210/interpreter.h>
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
using namespace nncase::runtime::k210;
|
||||
|
||||
interpreter::interpreter()
|
||||
#if NNCASE_TARGET_K210_SIMULATOR
|
||||
: kpu_mem_(std::make_unique<uint8_t[]>(2 * 1024 * 1024))
|
||||
#endif
|
||||
{
|
||||
#if !NNCASE_TARGET_K210_SIMULATOR
|
||||
kpu->interrupt_clear.reg = 7;
|
||||
kpu->interrupt_mask.reg = 7;
|
||||
kpu->fifo_threshold.reg = 10 | (1 << 4);
|
||||
kpu->eight_bit_mode.reg = 1;
|
||||
|
||||
plic_set_priority(IRQN_AI_INTERRUPT, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
xtl::span<uint8_t> interpreter::memory_at(const memory_range &range) const noexcept
|
||||
{
|
||||
if (range.memory_type == mem_k210_kpu)
|
||||
{
|
||||
uintptr_t base =
|
||||
#if NNCASE_TARGET_K210_SIMULATOR
|
||||
(uintptr_t)kpu_mem_.get();
|
||||
#else
|
||||
(uintptr_t)AI_IO_BASE_ADDR;
|
||||
#endif
|
||||
return { reinterpret_cast<uint8_t *>(base + range.start), range.size };
|
||||
}
|
||||
|
||||
return interpreter_base::memory_at(range);
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <kernels/k210/k210_kernels.h>
|
||||
#include <runtime/k210/k210_ops_body.h>
|
||||
#include <runtime/kernel_registry.h>
|
||||
#if !NNCASE_TARGET_K210_SIMULATOR
|
||||
#include <dmac.h>
|
||||
#include <sysctl.h>
|
||||
#endif
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
using namespace nncase::runtime::k210;
|
||||
|
||||
namespace
|
||||
{
|
||||
#if !NNCASE_TARGET_K210_SIMULATOR
|
||||
void kpu_send_layer(const kpu_layer_argument_t &layer)
|
||||
{
|
||||
kpu->layer_argument_fifo = layer.interrupt_enabe.reg;
|
||||
kpu->layer_argument_fifo = layer.image_addr.reg;
|
||||
kpu->layer_argument_fifo = layer.image_channel_num.reg;
|
||||
kpu->layer_argument_fifo = layer.image_size.reg;
|
||||
kpu->layer_argument_fifo = layer.kernel_pool_type_cfg.reg;
|
||||
kpu->layer_argument_fifo = layer.kernel_load_cfg.reg;
|
||||
kpu->layer_argument_fifo = layer.kernel_offset.reg;
|
||||
kpu->layer_argument_fifo = layer.kernel_calc_type_cfg.reg;
|
||||
kpu->layer_argument_fifo = layer.write_back_cfg.reg;
|
||||
kpu->layer_argument_fifo = layer.conv_value.reg;
|
||||
kpu->layer_argument_fifo = layer.conv_value2.reg;
|
||||
kpu->layer_argument_fifo = layer.dma_parameter.reg;
|
||||
}
|
||||
|
||||
void kpu_conv2d_normal(kpu_layer_argument_t &layer, plic_irq_callback_t callback, void *userdata)
|
||||
{
|
||||
kpu->interrupt_clear.reg = 0b111;
|
||||
kpu->interrupt_mask.reg = 0b110;
|
||||
layer.interrupt_enabe.data.int_en = 1;
|
||||
plic_irq_register(IRQN_AI_INTERRUPT, callback, userdata);
|
||||
plic_irq_enable(IRQN_AI_INTERRUPT);
|
||||
kpu_send_layer(layer);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
void kpu_conv2d_output(kpu_layer_argument_t &layer, dmac_channel_number_t dma_ch, uint8_t *dest, plic_irq_callback_t callback, void *userdata)
|
||||
{
|
||||
kpu->interrupt_clear.reg = 0b111;
|
||||
kpu->interrupt_mask.reg = 0b111;
|
||||
layer.dma_parameter.data.send_data_out = 1;
|
||||
sysctl_dma_select((sysctl_dma_channel_t)dma_ch, SYSCTL_DMA_SELECT_AI_RX_REQ);
|
||||
dmac_set_irq(dma_ch, callback, userdata, 1);
|
||||
dmac_set_single_mode(dma_ch, (void *)(&kpu->fifo_data_out), dest, DMAC_ADDR_NOCHANGE, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_8, DMAC_TRANS_WIDTH_64, (layer.dma_parameter.data.dma_total_byte + 8) / 8);
|
||||
kpu_send_layer(layer);
|
||||
}
|
||||
|
||||
int kpu_plic_thunk(void *userdata)
|
||||
{
|
||||
kpu->interrupt_clear.reg = 0b111;
|
||||
kpu->interrupt_mask.reg = 0b111;
|
||||
|
||||
auto &ctx = *reinterpret_cast<k210_interpreter_context *>(userdata);
|
||||
(ctx.interpreter->*ctx.step)();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kpu_upload_dma(dmac_channel_number_t dma_ch, const uint8_t *src, uint8_t *dest, size_t input_size, plic_irq_callback_t callback, void *userdata)
|
||||
{
|
||||
dmac_set_irq(dma_ch, callback, userdata, 1);
|
||||
dmac_set_single_mode(dma_ch, (void *)src, (void *)dest, DMAC_ADDR_INCREMENT, DMAC_ADDR_INCREMENT,
|
||||
DMAC_MSIZE_16, DMAC_TRANS_WIDTH_64, input_size / 8);
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
int kpu_dma_plic_thunk(void *userdata)
|
||||
{
|
||||
auto &ctx = *reinterpret_cast<k210_interpreter_context *>(userdata);
|
||||
(ctx.interpreter->*ctx.step)();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace k210
|
||||
{
|
||||
kernel_call_result kpu_upload(kpu_upload_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
#if !NNCASE_TARGET_K210_SIMULATOR
|
||||
if (options.in_shape[3] % 64 == 0)
|
||||
{
|
||||
auto &ctx = interpreter.context();
|
||||
ctx.interpreter = &interpreter;
|
||||
ctx.step = step;
|
||||
kpu_upload_dma(interpreter.dma_ch(), input.data(), output.data(), input.size(), kpu_dma_plic_thunk, &ctx);
|
||||
return kcr_async;
|
||||
}
|
||||
#endif
|
||||
kernels::k210::kpu_upload(input.data(), output.data(), options.in_shape);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result kpu_conv2d(kpu_conv2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
#if NNCASE_TARGET_K210_SIMULATOR
|
||||
auto input = interpreter.memory_at<uint8_t>({ mem_k210_kpu, dt_uint8, (uint32_t)options.layer.image_addr.data.image_src_addr * 64, 1 });
|
||||
auto kpu_out = interpreter.memory_at<uint8_t>({ mem_k210_kpu, dt_uint8, (uint32_t)options.layer.image_addr.data.image_dst_addr * 64, 1 });
|
||||
|
||||
auto in_h = static_cast<int32_t>(options.layer.image_size.data.i_col_high + 1);
|
||||
auto in_w = static_cast<int32_t>(options.layer.image_size.data.i_row_wid + 1);
|
||||
auto in_ch = static_cast<int32_t>(options.layer.image_channel_num.data.i_ch_num + 1);
|
||||
runtime_shape_t in_shape { options.batches, in_ch, in_h, in_w };
|
||||
auto in_fmap_size = kernels::details::compute_size(in_shape);
|
||||
|
||||
auto out_h = static_cast<int32_t>(options.layer.image_size.data.o_col_high + 1);
|
||||
auto out_w = static_cast<int32_t>(options.layer.image_size.data.o_row_wid + 1);
|
||||
auto out_ch = static_cast<int32_t>(options.layer.image_channel_num.data.o_ch_num + 1);
|
||||
runtime_shape_t conv_out_shape { options.batches, out_ch, in_h, in_w };
|
||||
auto conv_out_fmap_size = kernels::details::compute_size(conv_out_shape);
|
||||
runtime_shape_t out_shape { options.batches, out_ch, out_h, out_w };
|
||||
auto out_fmap_size = kernels::details::compute_size(out_shape);
|
||||
|
||||
auto input_tmp = std::make_unique<uint8_t[]>(in_fmap_size);
|
||||
auto workspace = std::make_unique<int64_t[]>(conv_out_fmap_size);
|
||||
auto conv_output_tmp = std::make_unique<uint8_t[]>(conv_out_fmap_size);
|
||||
auto output_tmp = std::make_unique<uint8_t[]>(out_fmap_size);
|
||||
|
||||
kernels::k210::kpu_download(input.data(), input_tmp.get(), in_shape);
|
||||
auto is_depthwise = options.layer.interrupt_enabe.data.depth_wise_layer != 0;
|
||||
auto filter_size = get_kpu_filter_size((kpu_filter_type_t)options.layer.kernel_pool_type_cfg.data.kernel_type);
|
||||
auto pad_value = (uint8_t)options.layer.kernel_pool_type_cfg.data.pad_value;
|
||||
auto arg_x = (int32_t)kernels::details::to_signed<24>(options.layer.conv_value.data.arg_x);
|
||||
auto shift_x = (int32_t)options.layer.conv_value.data.shr_x;
|
||||
auto arg_w = (int32_t)kernels::details::to_signed<24>(options.layer.conv_value.data.arg_w);
|
||||
auto shift_w = (int32_t)options.layer.conv_value.data.shr_w;
|
||||
auto arg_add = kernels::details::to_signed<40>(options.layer.conv_value2.data.arg_add);
|
||||
|
||||
auto batchnorm = std::make_unique<kpu_batchnorm_segment[]>(out_ch);
|
||||
for (size_t i = 0; i < out_ch; i++)
|
||||
{
|
||||
auto &src = options.batch_norm[i].batchnorm.data;
|
||||
auto &dest = batchnorm[i];
|
||||
dest.mul = (int32_t)kernels::details::to_signed<24>(src.norm_mul);
|
||||
dest.shift = (int32_t)src.norm_shift;
|
||||
dest.add = (int32_t)kernels::details::to_signed<32>(src.norm_add);
|
||||
}
|
||||
|
||||
kpu_activation_table_t activation;
|
||||
for (size_t i = 0; i < 16; i++)
|
||||
{
|
||||
auto &src = options.activation->activate_para[i].data;
|
||||
auto &dest = activation[i];
|
||||
dest.start_x = kernels::details::to_signed<36>(src.x_start);
|
||||
dest.mul = (int32_t)kernels::details::to_signed<16>(src.y_mul);
|
||||
dest.shift = (int32_t)src.shift_number;
|
||||
|
||||
if (i < 16)
|
||||
dest.add = options.activation->activate_para_bias0.data.result_bias[i];
|
||||
else
|
||||
dest.add = options.activation->activate_para_bias1.data.result_bias[i - 16];
|
||||
}
|
||||
|
||||
#define KPU_CONV2D_IMPL(is_depthwise_val, filter_size_val) \
|
||||
if (is_depthwise == is_depthwise_val && filter_size == filter_size_val) \
|
||||
kernels::k210::kpu_conv2d<is_depthwise_val, filter_size_val>(input_tmp.get(), workspace.get(), conv_output_tmp.get(), options.weights.data(), \
|
||||
in_h, in_w, in_ch, out_ch, pad_value, arg_x, shift_x, arg_w, shift_w, arg_add, batchnorm.get(), activation)
|
||||
|
||||
KPU_CONV2D_IMPL(true, 1);
|
||||
else KPU_CONV2D_IMPL(true, 3);
|
||||
else KPU_CONV2D_IMPL(false, 1);
|
||||
else KPU_CONV2D_IMPL(false, 3);
|
||||
|
||||
kernels::k210::kpu_pool2d(conv_output_tmp.get(), output_tmp.get(), in_h, in_w, out_ch, (kpu_pool_type_t)options.layer.kernel_pool_type_cfg.data.pool_type);
|
||||
kernels::k210::kpu_upload(output_tmp.get(), kpu_out.data(), out_shape);
|
||||
if (options.main_mem_output.size)
|
||||
{
|
||||
auto main_output = interpreter.memory_at<uint8_t>(options.main_mem_output);
|
||||
std::copy(output_tmp.get(), output_tmp.get() + out_fmap_size, main_output.data());
|
||||
}
|
||||
|
||||
return kcr_done;
|
||||
#else
|
||||
auto &ctx = interpreter.context();
|
||||
ctx.interpreter = &interpreter;
|
||||
ctx.step = step;
|
||||
|
||||
if (options.main_mem_output.size)
|
||||
{
|
||||
auto main_output = interpreter.memory_at<uint8_t>(options.main_mem_output);
|
||||
kpu_conv2d_output(options.layer, interpreter.dma_ch(), main_output.data(), kpu_plic_thunk, &ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
kpu_conv2d_normal(options.layer, kpu_plic_thunk, &ctx);
|
||||
}
|
||||
|
||||
return kcr_async;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <runtime/cpu/cpu_ops_body.h>
|
||||
#include <runtime/k210/k210_ops_body.h>
|
||||
#include <runtime/kernel_registry.h>
|
||||
#include <runtime/neutral/neutral_ops_body.h>
|
||||
#include <runtime/span_reader.h>
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
#define BEGINE_DEFINE_TARGET(target) \
|
||||
namespace target \
|
||||
{
|
||||
|
||||
#define DEFINE_NEUTRAL_RUNTIME_OP(id, name, value) \
|
||||
kernel_call_result id(id##_options &, interpreter_t &, interpreter_step_t);
|
||||
#define DEFINE_RUNTIME_OP(target, id, name, value) \
|
||||
kernel_call_result id(id##_options &, interpreter_t &, interpreter_step_t);
|
||||
|
||||
#define END_DEFINE_TARGET() }
|
||||
|
||||
#include <runtime/runtime_op.def>
|
||||
|
||||
#undef BEGINE_DEFINE_TARGET
|
||||
#undef DEFINE_NEUTRAL_RUNTIME_OP
|
||||
#undef DEFINE_RUNTIME_OP
|
||||
#undef END_DEFINE_TARGET
|
||||
}
|
||||
}
|
||||
|
||||
kernel_call_result runtime::call_kernel(runtime_opcode opcode, xtl::span<const uint8_t> body, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
span_reader reader(body);
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
#define BEGINE_DEFINE_TARGET(...)
|
||||
#define DEFINE_NEUTRAL_RUNTIME_OP(id, name, value) \
|
||||
case rop_##id: \
|
||||
{ \
|
||||
nncase::runtime::neutral::id##_options options; \
|
||||
options.deserialize(reader); \
|
||||
return nncase::runtime::neutral::id(options, interpreter, step); \
|
||||
}
|
||||
#define DEFINE_RUNTIME_OP(target, id, name, value) \
|
||||
case rop_##target##_##id: \
|
||||
{ \
|
||||
nncase::runtime::target::id##_options options; \
|
||||
options.deserialize(reader); \
|
||||
return nncase::runtime::target::id(options, interpreter, step); \
|
||||
}
|
||||
#define END_DEFINE_TARGET()
|
||||
|
||||
#include <runtime/runtime_op.def>
|
||||
|
||||
#undef BEGINE_DEFINE_TARGET
|
||||
#undef DEFINE_NEUTRAL_RUNTIME_OP
|
||||
#undef DEFINE_RUNTIME_OP
|
||||
#undef END_DEFINE_TARGET
|
||||
default:
|
||||
return kcr_error;
|
||||
}
|
||||
}
|
|
@ -1,309 +0,0 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <kernels/neutral/neutral_kernels.h>
|
||||
#include <runtime/kernel_registry.h>
|
||||
#include <runtime/neutral/neutral_ops_body.h>
|
||||
|
||||
using namespace nncase;
|
||||
using namespace nncase::runtime;
|
||||
|
||||
#define ELEM_SIZE_IMPL(type, KERNEL) \
|
||||
switch (runtime::get_bytes(type)) \
|
||||
{ \
|
||||
case 1: \
|
||||
KERNEL(uint8_t); \
|
||||
break; \
|
||||
case 2: \
|
||||
KERNEL(uint16_t); \
|
||||
break; \
|
||||
case 4: \
|
||||
KERNEL(uint32_t); \
|
||||
break; \
|
||||
default: \
|
||||
return kcr_error; \
|
||||
}
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace neutral
|
||||
{
|
||||
kernel_call_result binary(binary_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input_a = interpreter.memory_at<float>(options.input_a);
|
||||
auto input_b = interpreter.memory_at<float>(options.input_b);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
auto binary = [&](auto op) {
|
||||
kernels::neutral::binary(input_a.data(), input_b.data(), output.data(), options.in_a_shape, options.in_b_shape, options.out_shape, options.fused_activation, op);
|
||||
};
|
||||
|
||||
switch (options.binary_op)
|
||||
{
|
||||
case binary_add:
|
||||
binary([](auto a, auto b) { return a + b; });
|
||||
return kcr_done;
|
||||
case binary_sub:
|
||||
binary([](auto a, auto b) { return a - b; });
|
||||
return kcr_done;
|
||||
case binary_mul:
|
||||
binary([](auto a, auto b) { return a * b; });
|
||||
return kcr_done;
|
||||
case binary_div:
|
||||
binary([](auto a, auto b) { return a / b; });
|
||||
return kcr_done;
|
||||
case binary_min:
|
||||
binary([](auto a, auto b) { return std::min(a, b); });
|
||||
return kcr_done;
|
||||
case binary_max:
|
||||
binary([](auto a, auto b) { return std::max(a, b); });
|
||||
return kcr_done;
|
||||
default:
|
||||
return kcr_error;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_call_result concat(concat_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
kernels::neutral::concat(options.inputs, output.data(), options.dims, options.inner_size, options.outer_size,
|
||||
[&](const memory_range &range) { return interpreter.memory_at<uint8_t>(range).data(); });
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result conv2d(conv2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
kernels::neutral::conv2d(input.data(), output.data(), options.weights.data(), options.bias.data(), options.in_shape, options.groups, options.out_channels, options.filter_h,
|
||||
options.filter_w, options.stride_h, options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w, options.fused_activation);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result dequantize(dequantize_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
kernels::neutral::dequantize(input.data(), output.data(), input.size(), options.quant_param);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result matmul(matmul_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input_a = interpreter.memory_at<float>(options.input_a);
|
||||
auto input_b = interpreter.memory_at<float>(options.input_b);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
kernels::neutral::matmul(input_a.data(), input_b.data(), output.data(), options.bias.data(), options.a_rows, options.a_cols, options.b_cols, options.fused_activation);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result memory_copy(memory_copy_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result pad(pad_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
|
||||
#define PAD_KERNEL(T) \
|
||||
kernels::neutral::pad(reinterpret_cast<const T *>(input.data()), reinterpret_cast<T *>(output.data()), options.in_shape, options.paddings, options.pad_value.as<T>());
|
||||
|
||||
ELEM_SIZE_IMPL(options.input.datatype, PAD_KERNEL);
|
||||
return kcr_done;
|
||||
#undef PAD_KERNEL
|
||||
}
|
||||
|
||||
kernel_call_result quantize(quantize_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
|
||||
kernels::neutral::quantize(input.data(), output.data(), input.size(), options.quant_param);
|
||||
return runtime::kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result reduce(reduce_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
auto reduce = [&](auto op) {
|
||||
kernels::neutral::reduce(input.data(), output.data(), options.init_value, options.in_shape, options.out_shape, op);
|
||||
};
|
||||
|
||||
switch (options.reduce_op)
|
||||
{
|
||||
case reduce_mean:
|
||||
{
|
||||
reduce([](auto a, auto b) { return a + b; });
|
||||
auto mul = (float)output.size() / input.size();
|
||||
kernels::neutral::unary(output.data(), output.data(), output.size(), [mul](auto a) { return a * mul; });
|
||||
return kcr_done;
|
||||
}
|
||||
case reduce_min:
|
||||
reduce([](auto a, auto b) { return std::min(a, b); });
|
||||
return kcr_done;
|
||||
case reduce_max:
|
||||
reduce([](auto a, auto b) { return std::max(a, b); });
|
||||
return kcr_done;
|
||||
case reduce_sum:
|
||||
reduce([](auto a, auto b) { return a + b; });
|
||||
return kcr_done;
|
||||
default:
|
||||
return kcr_error;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_call_result reduce_window2d(reduce_window2d_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
auto reduce = [&](auto binary_op, auto window_op) {
|
||||
kernels::neutral::reduce_window2d(input.data(), output.data(), options.init_value, options.in_shape, options.filter_h, options.filter_w, options.stride_h,
|
||||
options.stride_w, options.dilation_h, options.dilation_w, options.padding_h, options.padding_w, options.fused_activation, binary_op, window_op);
|
||||
};
|
||||
|
||||
switch (options.reduce_op)
|
||||
{
|
||||
case reduce_mean:
|
||||
reduce([](auto a, auto b) { return a + b; }, [](auto v, auto k) { return v / k; });
|
||||
return kcr_done;
|
||||
case reduce_min:
|
||||
reduce([](auto a, auto b) { return std::min(a, b); }, [](auto v, auto k) { return v; });
|
||||
return kcr_done;
|
||||
case reduce_max:
|
||||
reduce([](auto a, auto b) { return std::max(a, b); }, [](auto v, auto k) { return v; });
|
||||
return kcr_done;
|
||||
case reduce_sum:
|
||||
reduce([](auto a, auto b) { return a + b; }, [](auto v, auto k) { return v; });
|
||||
return kcr_done;
|
||||
default:
|
||||
return kcr_error;
|
||||
}
|
||||
}
|
||||
|
||||
kernel_call_result resize_image(resize_image_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
if (options.mode == image_resize_bilinear)
|
||||
{
|
||||
kernels::neutral::resize_bilinear(input.data(), output.data(), options.in_shape, options.out_h, options.out_w, options.align_corners);
|
||||
return kcr_done;
|
||||
}
|
||||
else
|
||||
{
|
||||
#define RESIZE_NN_KERNEL(T) \
|
||||
kernels::neutral::resize_nearest_neighbor(reinterpret_cast<const T *>(input.data()), reinterpret_cast<T *>(output.data()), options.in_shape, options.out_h, options.out_w);
|
||||
|
||||
ELEM_SIZE_IMPL(options.input.datatype, RESIZE_NN_KERNEL);
|
||||
return kcr_done;
|
||||
#undef RESIZE_NN_KERNEL
|
||||
}
|
||||
}
|
||||
|
||||
kernel_call_result softmax(softmax_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
kernels::neutral::softmax(input.data(), output.data(), options.beta, options.outer_size, options.inner_size);
|
||||
return kcr_done;
|
||||
}
|
||||
|
||||
kernel_call_result transpose(transpose_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
|
||||
#define TRANSPOSE_KERNEL(T) \
|
||||
kernels::neutral::transpose(reinterpret_cast<const T *>(input.data()), reinterpret_cast<T *>(output.data()), options.in_shape, options.perm);
|
||||
|
||||
ELEM_SIZE_IMPL(options.input.datatype, TRANSPOSE_KERNEL);
|
||||
return kcr_done;
|
||||
#undef TRANSPOSE_KERNEL
|
||||
}
|
||||
|
||||
kernel_call_result strided_slice(strided_slice_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<uint8_t>(options.input);
|
||||
auto output = interpreter.memory_at<uint8_t>(options.output);
|
||||
|
||||
#define STRIDED_SLICE_KERNEL(T) \
|
||||
kernels::neutral::strided_slice(reinterpret_cast<const T *>(input.data()), reinterpret_cast<T *>(output.data()), options.in_shape, options.begin, options.end, options.strides);
|
||||
|
||||
ELEM_SIZE_IMPL(options.input.datatype, STRIDED_SLICE_KERNEL);
|
||||
return kcr_done;
|
||||
#undef STRIDED_SLICE_KERNEL
|
||||
}
|
||||
|
||||
kernel_call_result unary(unary_options &options, interpreter_t &interpreter, interpreter_step_t step)
|
||||
{
|
||||
auto input = interpreter.memory_at<float>(options.input);
|
||||
auto output = interpreter.memory_at<float>(options.output);
|
||||
|
||||
auto unary = [&](auto unary_op) {
|
||||
kernels::neutral::unary(input.data(), output.data(), input.size(), unary_op);
|
||||
};
|
||||
|
||||
switch (options.unary_op)
|
||||
{
|
||||
case unary_abs:
|
||||
unary([](auto a) { return fabs(a); });
|
||||
return kcr_done;
|
||||
case unary_ceil:
|
||||
unary([](auto a) { return ceilf(a); });
|
||||
return kcr_done;
|
||||
case unary_cos:
|
||||
unary([](auto a) { return cosf(a); });
|
||||
return kcr_done;
|
||||
case unary_exp:
|
||||
unary([](auto a) { return expf(a); });
|
||||
return kcr_done;
|
||||
case unary_floor:
|
||||
unary([](auto a) { return floorf(a); });
|
||||
return kcr_done;
|
||||
case unary_log:
|
||||
unary([](auto a) { return logf(a); });
|
||||
return kcr_done;
|
||||
case unary_neg:
|
||||
unary([](auto a) { return -a; });
|
||||
return kcr_done;
|
||||
case unary_rsqrt:
|
||||
unary([](auto a) { return 1.f / sqrtf(a); });
|
||||
return kcr_done;
|
||||
case unary_sin:
|
||||
unary([](auto a) { return sinf(a); });
|
||||
return kcr_done;
|
||||
case unary_square:
|
||||
unary([](auto a) { return a * a; });
|
||||
return kcr_done;
|
||||
default:
|
||||
return kcr_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
DVP
|
||||
=====
|
||||
Display the real-time image from ov5640.
|
||||
=====
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef _BOARD_CONFIG_
|
||||
#define _BOARD_CONFIG_
|
||||
|
||||
#define OV5640 1
|
||||
#define OV2640 0
|
||||
|
||||
#define BOARD_KD233 1
|
||||
#define BOARD_LICHEEDAN 0
|
||||
#define BOARD_K61 0
|
||||
|
||||
#if (OV5640 && OV2640) || (!OV5640 && !OV2640)
|
||||
#error ov sensor only choose one
|
||||
#endif
|
||||
|
||||
#if (BOARD_LICHEEDAN && BOARD_KD233) || (BOARD_LICHEEDAN && BOARD_K61) || (BOARD_K61 && BOARD_KD233) || (!BOARD_LICHEEDAN && !BOARD_KD233 && !BOARD_K61)
|
||||
#error board only choose one
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,366 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _FONT_H_
|
||||
#define _FONT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t const ascii0816[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD,
|
||||
0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF,
|
||||
0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE,
|
||||
0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
|
||||
0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
|
||||
0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD,
|
||||
0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E,
|
||||
0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30,
|
||||
0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63,
|
||||
0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8,
|
||||
0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E,
|
||||
0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB,
|
||||
0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6,
|
||||
0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
|
||||
0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
|
||||
0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C,
|
||||
0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
|
||||
0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C,
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C,
|
||||
0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE,
|
||||
0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
|
||||
0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
|
||||
0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
|
||||
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00,
|
||||
0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
|
||||
0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE,
|
||||
0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
|
||||
0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
|
||||
0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
|
||||
0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE,
|
||||
0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66,
|
||||
0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C,
|
||||
0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C,
|
||||
0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
|
||||
0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38,
|
||||
0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
|
||||
0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60,
|
||||
0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60,
|
||||
0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60,
|
||||
0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6,
|
||||
0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60,
|
||||
0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
|
||||
0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
|
||||
0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6,
|
||||
0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
|
||||
0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
|
||||
0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE,
|
||||
0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C,
|
||||
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38,
|
||||
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06,
|
||||
0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE,
|
||||
0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
|
||||
0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66,
|
||||
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6,
|
||||
0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00,
|
||||
0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36,
|
||||
0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C,
|
||||
0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
|
||||
0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
|
||||
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00,
|
||||
0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C,
|
||||
0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
|
||||
0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC,
|
||||
0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30,
|
||||
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC,
|
||||
0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
|
||||
0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
|
||||
0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xDC, 0x86, 0x0C,
|
||||
0x18, 0x3E, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
|
||||
0x66, 0xCE, 0x9E, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36,
|
||||
0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
|
||||
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
|
||||
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
||||
0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
|
||||
0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xC6, 0xC6, 0xCC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8,
|
||||
0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66,
|
||||
0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
|
||||
0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66,
|
||||
0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xDB, 0xDB, 0xF3, 0x7E, 0x60, 0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60,
|
||||
0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C,
|
||||
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
|
||||
0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
|
||||
0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00,
|
||||
0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
|
||||
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "lcd.h"
|
||||
#include "nt35310.h"
|
||||
#include "font.h"
|
||||
#include "board_config.h"
|
||||
|
||||
static lcd_ctl_t lcd_ctl;
|
||||
|
||||
void lcd_polling_enable(void)
|
||||
{
|
||||
lcd_ctl.mode = 0;
|
||||
}
|
||||
|
||||
void lcd_interrupt_enable(void)
|
||||
{
|
||||
lcd_ctl.mode = 1;
|
||||
}
|
||||
|
||||
void lcd_init(void)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
|
||||
tft_hard_init();
|
||||
/*soft reset*/
|
||||
tft_write_command(SOFTWARE_RESET);
|
||||
usleep(100000);
|
||||
/*exit sleep*/
|
||||
tft_write_command(SLEEP_OFF);
|
||||
usleep(100000);
|
||||
/*pixel format*/
|
||||
tft_write_command(PIXEL_FORMAT_SET);
|
||||
data = 0x55;
|
||||
tft_write_byte(&data, 1);
|
||||
lcd_set_direction(DIR_XY_LRUD);
|
||||
|
||||
/*display on*/
|
||||
tft_write_command(DISPALY_ON);
|
||||
lcd_polling_enable();
|
||||
}
|
||||
|
||||
void lcd_set_direction(lcd_dir_t dir)
|
||||
{
|
||||
#if !BOARD_LICHEEDAN
|
||||
dir |= 0x08;
|
||||
#endif
|
||||
lcd_ctl.dir = dir;
|
||||
if (dir & DIR_XY_MASK)
|
||||
{
|
||||
lcd_ctl.width = LCD_Y_MAX - 1;
|
||||
lcd_ctl.height = LCD_X_MAX - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lcd_ctl.width = LCD_X_MAX - 1;
|
||||
lcd_ctl.height = LCD_Y_MAX - 1;
|
||||
}
|
||||
|
||||
tft_write_command(MEMORY_ACCESS_CTL);
|
||||
tft_write_byte((uint8_t *)&dir, 1);
|
||||
}
|
||||
|
||||
void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
|
||||
{
|
||||
uint8_t data[4] = {0};
|
||||
|
||||
data[0] = (uint8_t)(x1 >> 8);
|
||||
data[1] = (uint8_t)(x1);
|
||||
data[2] = (uint8_t)(x2 >> 8);
|
||||
data[3] = (uint8_t)(x2);
|
||||
tft_write_command(HORIZONTAL_ADDRESS_SET);
|
||||
tft_write_byte(data, 4);
|
||||
|
||||
data[0] = (uint8_t)(y1 >> 8);
|
||||
data[1] = (uint8_t)(y1);
|
||||
data[2] = (uint8_t)(y2 >> 8);
|
||||
data[3] = (uint8_t)(y2);
|
||||
tft_write_command(VERTICAL_ADDRESS_SET);
|
||||
tft_write_byte(data, 4);
|
||||
|
||||
tft_write_command(MEMORY_WRITE);
|
||||
}
|
||||
|
||||
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
|
||||
{
|
||||
lcd_set_area(x, y, x, y);
|
||||
tft_write_half(&color, 1);
|
||||
}
|
||||
|
||||
void lcd_draw_char(uint16_t x, uint16_t y, char c, uint16_t color)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint8_t j = 0;
|
||||
uint8_t data = 0;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
data = ascii0816[c * 16 + i];
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if (data & 0x80)
|
||||
lcd_draw_point(x + j, y, color);
|
||||
data <<= 1;
|
||||
}
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
lcd_draw_char(x, y, *str, color);
|
||||
str++;
|
||||
x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint8_t j = 0;
|
||||
uint8_t data = 0;
|
||||
uint8_t *pdata = NULL;
|
||||
uint16_t width = 0;
|
||||
uint32_t *pixel = NULL;
|
||||
|
||||
width = 4 * strlen(str);
|
||||
while (*str)
|
||||
{
|
||||
pdata = (uint8_t *)&ascii0816[(*str) * 16];
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
data = *pdata++;
|
||||
pixel = ptr + i * width;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
switch (data >> 6)
|
||||
{
|
||||
case 0:
|
||||
*pixel = ((uint32_t)bg_color << 16) | bg_color;
|
||||
break;
|
||||
case 1:
|
||||
*pixel = ((uint32_t)bg_color << 16) | font_color;
|
||||
break;
|
||||
case 2:
|
||||
*pixel = ((uint32_t)font_color << 16) | bg_color;
|
||||
break;
|
||||
case 3:
|
||||
*pixel = ((uint32_t)font_color << 16) | font_color;
|
||||
break;
|
||||
default:
|
||||
*pixel = 0;
|
||||
break;
|
||||
}
|
||||
data <<= 2;
|
||||
pixel++;
|
||||
}
|
||||
}
|
||||
str++;
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_clear(uint16_t color)
|
||||
{
|
||||
uint32_t data = ((uint32_t)color << 16) | (uint32_t)color;
|
||||
|
||||
lcd_set_area(0, 0, lcd_ctl.width, lcd_ctl.height);
|
||||
tft_fill_data(&data, LCD_X_MAX * LCD_Y_MAX / 2);
|
||||
}
|
||||
|
||||
void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color)
|
||||
{
|
||||
uint32_t data_buf[640] = {0};
|
||||
uint32_t *p = data_buf;
|
||||
uint32_t data = color;
|
||||
uint32_t index = 0;
|
||||
|
||||
data = (data << 16) | data;
|
||||
for (index = 0; index < 160 * width; index++)
|
||||
*p++ = data;
|
||||
|
||||
lcd_set_area(x1, y1, x2, y1 + width - 1);
|
||||
tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0);
|
||||
lcd_set_area(x1, y2 - width + 1, x2, y2);
|
||||
tft_write_word(data_buf, ((x2 - x1 + 1) * width + 1) / 2, 0);
|
||||
lcd_set_area(x1, y1, x1 + width - 1, y2);
|
||||
tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0);
|
||||
lcd_set_area(x2 - width + 1, y1, x2, y2);
|
||||
tft_write_word(data_buf, ((y2 - y1 + 1) * width + 1) / 2, 0);
|
||||
}
|
||||
|
||||
void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr)
|
||||
{
|
||||
lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1);
|
||||
tft_write_word(ptr, width * height / 2, lcd_ctl.mode ? 2 : 0);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _LCD_H_
|
||||
#define _LCD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* clang-format off */
|
||||
#define LCD_X_MAX (240)
|
||||
#define LCD_Y_MAX (320)
|
||||
|
||||
#define BLACK 0x0000
|
||||
#define NAVY 0x000F
|
||||
#define DARKGREEN 0x03E0
|
||||
#define DARKCYAN 0x03EF
|
||||
#define MAROON 0x7800
|
||||
#define PURPLE 0x780F
|
||||
#define OLIVE 0x7BE0
|
||||
#define LIGHTGREY 0xC618
|
||||
#define DARKGREY 0x7BEF
|
||||
#define BLUE 0x001F
|
||||
#define GREEN 0x07E0
|
||||
#define CYAN 0x07FF
|
||||
#define RED 0xF800
|
||||
#define MAGENTA 0xF81F
|
||||
#define YELLOW 0xFFE0
|
||||
#define WHITE 0xFFFF
|
||||
#define ORANGE 0xFD20
|
||||
#define GREENYELLOW 0xAFE5
|
||||
#define PINK 0xF81F
|
||||
#define USER_COLOR 0xAA55
|
||||
/* clang-format on */
|
||||
|
||||
typedef enum _lcd_dir
|
||||
{
|
||||
DIR_XY_RLUD = 0x00,
|
||||
DIR_YX_RLUD = 0x20,
|
||||
DIR_XY_LRUD = 0x40,
|
||||
DIR_YX_LRUD = 0x60,
|
||||
DIR_XY_RLDU = 0x80,
|
||||
DIR_YX_RLDU = 0xA0,
|
||||
DIR_XY_LRDU = 0xC0,
|
||||
DIR_YX_LRDU = 0xE0,
|
||||
DIR_XY_MASK = 0x20,
|
||||
DIR_MASK = 0xE0,
|
||||
} lcd_dir_t;
|
||||
|
||||
typedef struct _lcd_ctl
|
||||
{
|
||||
uint8_t mode;
|
||||
uint8_t dir;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} lcd_ctl_t;
|
||||
|
||||
void lcd_polling_enable(void);
|
||||
void lcd_interrupt_enable(void);
|
||||
void lcd_init(void);
|
||||
void lcd_clear(uint16_t color);
|
||||
void lcd_set_direction(lcd_dir_t dir);
|
||||
void lcd_set_area(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
|
||||
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color);
|
||||
void lcd_draw_string(uint16_t x, uint16_t y, char *str, uint16_t color);
|
||||
void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr);
|
||||
void lcd_draw_rectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color);
|
||||
void lcd_ram_draw_string(char *str, uint32_t *ptr, uint16_t font_color, uint16_t bg_color);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "dvp.h"
|
||||
#include "fpioa.h"
|
||||
#include "lcd.h"
|
||||
#include "ov5640.h"
|
||||
#include "ov2640.h"
|
||||
#include "plic.h"
|
||||
#include "sysctl.h"
|
||||
#include "uarths.h"
|
||||
#include "nt35310.h"
|
||||
#include "board_config.h"
|
||||
#include "unistd.h"
|
||||
#include "utils.h"
|
||||
#include "iomem_malloc.h"
|
||||
|
||||
uint32_t *g_lcd_gram0_io;
|
||||
uint32_t *g_lcd_gram1_io;
|
||||
|
||||
volatile uint8_t g_dvp_finish_flag;
|
||||
volatile uint8_t g_ram_mux;
|
||||
|
||||
static int on_irq_dvp(void* ctx)
|
||||
{
|
||||
if (dvp_get_interrupt(DVP_STS_FRAME_FINISH))
|
||||
{
|
||||
/* switch gram */
|
||||
dvp_set_display_addr(g_ram_mux ? (uint32_t)g_lcd_gram0_io : (uint32_t)g_lcd_gram1_io);
|
||||
|
||||
dvp_clear_interrupt(DVP_STS_FRAME_FINISH);
|
||||
g_dvp_finish_flag = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(g_dvp_finish_flag == 0)
|
||||
dvp_start_convert();
|
||||
dvp_clear_interrupt(DVP_STS_FRAME_START);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void io_mux_init(void)
|
||||
{
|
||||
|
||||
#if BOARD_LICHEEDAN
|
||||
/* Init DVP IO map and function settings */
|
||||
fpioa_set_function(42, FUNC_CMOS_RST);
|
||||
fpioa_set_function(44, FUNC_CMOS_PWDN);
|
||||
fpioa_set_function(46, FUNC_CMOS_XCLK);
|
||||
fpioa_set_function(43, FUNC_CMOS_VSYNC);
|
||||
fpioa_set_function(45, FUNC_CMOS_HREF);
|
||||
fpioa_set_function(47, FUNC_CMOS_PCLK);
|
||||
fpioa_set_function(41, FUNC_SCCB_SCLK);
|
||||
fpioa_set_function(40, FUNC_SCCB_SDA);
|
||||
|
||||
/* Init SPI IO map and function settings */
|
||||
fpioa_set_function(38, FUNC_GPIOHS0 + DCX_GPIONUM);
|
||||
fpioa_set_function(36, FUNC_SPI0_SS3);
|
||||
fpioa_set_function(39, FUNC_SPI0_SCLK);
|
||||
fpioa_set_function(37, FUNC_GPIOHS0 + RST_GPIONUM);
|
||||
|
||||
sysctl_set_spi0_dvp_data(1);
|
||||
#else
|
||||
/* Init DVP IO map and function settings */
|
||||
fpioa_set_function(11, FUNC_CMOS_RST);
|
||||
fpioa_set_function(13, FUNC_CMOS_PWDN);
|
||||
fpioa_set_function(14, FUNC_CMOS_XCLK);
|
||||
fpioa_set_function(12, FUNC_CMOS_VSYNC);
|
||||
fpioa_set_function(17, FUNC_CMOS_HREF);
|
||||
fpioa_set_function(15, FUNC_CMOS_PCLK);
|
||||
fpioa_set_function(10, FUNC_SCCB_SCLK);
|
||||
fpioa_set_function(9, FUNC_SCCB_SDA);
|
||||
|
||||
/* Init SPI IO map and function settings */
|
||||
fpioa_set_function(8, FUNC_GPIOHS0 + DCX_GPIONUM);
|
||||
fpioa_set_function(6, FUNC_SPI0_SS3);
|
||||
fpioa_set_function(7, FUNC_SPI0_SCLK);
|
||||
|
||||
sysctl_set_spi0_dvp_data(1);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void io_set_power(void)
|
||||
{
|
||||
#if BOARD_LICHEEDAN
|
||||
/* Set dvp and spi pin to 1.8V */
|
||||
sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
|
||||
sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
|
||||
|
||||
#else
|
||||
/* Set dvp and spi pin to 1.8V */
|
||||
sysctl_set_power_mode(SYSCTL_POWER_BANK1, SYSCTL_POWER_V18);
|
||||
sysctl_set_power_mode(SYSCTL_POWER_BANK2, SYSCTL_POWER_V18);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
g_lcd_gram0_io = (uint32_t *)iomem_malloc(320 * 240 * 2);
|
||||
g_lcd_gram1_io = (uint32_t *)iomem_malloc(320 * 240 * 2);
|
||||
/* Set CPU and dvp clk */
|
||||
sysctl_pll_set_freq(SYSCTL_PLL0, 800000000UL);
|
||||
sysctl_pll_set_freq(SYSCTL_PLL1, 160000000UL);
|
||||
sysctl_pll_set_freq(SYSCTL_PLL2, 45158400UL);
|
||||
uarths_init();
|
||||
|
||||
io_mux_init();
|
||||
io_set_power();
|
||||
plic_init();
|
||||
|
||||
/* LCD init */
|
||||
printf("LCD init\n");
|
||||
lcd_init();
|
||||
#if BOARD_LICHEEDAN
|
||||
lcd_set_direction(DIR_YX_RLDU);
|
||||
#else
|
||||
lcd_set_direction(DIR_YX_RLUD);
|
||||
#endif
|
||||
|
||||
lcd_clear(BLACK);
|
||||
|
||||
/* DVP init */
|
||||
printf("DVP init\n");
|
||||
#if OV5640
|
||||
dvp_init(16);
|
||||
dvp_set_xclk_rate(50000000);
|
||||
dvp_enable_burst();
|
||||
dvp_set_output_enable(0, 1);
|
||||
dvp_set_output_enable(1, 1);
|
||||
dvp_set_image_format(DVP_CFG_RGB_FORMAT);
|
||||
dvp_set_image_size(320, 240);
|
||||
ov5640_init();
|
||||
|
||||
#if 0
|
||||
// OV5640_Focus_Init();
|
||||
OV5640_Light_Mode(2); //set auto
|
||||
OV5640_Color_Saturation(6); //default
|
||||
OV5640_Brightness(8); //default
|
||||
OV5640_Contrast(3); //default
|
||||
// OV5640_Sharpness(33); //set auto
|
||||
// OV5640_Auto_Focus();
|
||||
#endif
|
||||
|
||||
#else
|
||||
dvp_init(8);
|
||||
dvp_set_xclk_rate(24000000);
|
||||
dvp_enable_burst();
|
||||
dvp_set_output_enable(0, 1);
|
||||
dvp_set_output_enable(1, 1);
|
||||
dvp_set_image_format(DVP_CFG_RGB_FORMAT);
|
||||
|
||||
dvp_set_image_size(320, 240);
|
||||
ov2640_init();
|
||||
#endif
|
||||
|
||||
dvp_set_ai_addr((uint32_t)0x40600000, (uint32_t)0x40612C00, (uint32_t)0x40625800);
|
||||
dvp_set_display_addr((uint32_t)g_lcd_gram0_io);
|
||||
dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 0);
|
||||
dvp_disable_auto();
|
||||
|
||||
/* DVP interrupt config */
|
||||
printf("DVP interrupt config\n");
|
||||
plic_set_priority(IRQN_DVP_INTERRUPT, 1);
|
||||
plic_irq_register(IRQN_DVP_INTERRUPT, on_irq_dvp, NULL);
|
||||
plic_irq_enable(IRQN_DVP_INTERRUPT);
|
||||
|
||||
/* enable global interrupt */
|
||||
sysctl_enable_irq();
|
||||
|
||||
/* system start */
|
||||
printf("system start\n");
|
||||
g_ram_mux = 0;
|
||||
g_dvp_finish_flag = 0;
|
||||
dvp_clear_interrupt(DVP_STS_FRAME_START | DVP_STS_FRAME_FINISH);
|
||||
dvp_config_interrupt(DVP_CFG_START_INT_ENABLE | DVP_CFG_FINISH_INT_ENABLE, 1);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* ai cal finish*/
|
||||
while (g_dvp_finish_flag == 0)
|
||||
;
|
||||
g_dvp_finish_flag = 0;
|
||||
/* display pic*/
|
||||
g_ram_mux ^= 0x01;
|
||||
lcd_draw_picture(0, 0, 320, 240, g_ram_mux ? g_lcd_gram0_io : g_lcd_gram1_io);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "nt35310.h"
|
||||
#include "gpiohs.h"
|
||||
#include "spi.h"
|
||||
#include "unistd.h"
|
||||
#include "board_config.h"
|
||||
|
||||
static void init_dcx(void)
|
||||
{
|
||||
gpiohs_set_drive_mode(DCX_GPIONUM, GPIO_DM_OUTPUT);
|
||||
gpiohs_set_pin(DCX_GPIONUM, GPIO_PV_HIGH);
|
||||
}
|
||||
|
||||
static void set_dcx_control(void)
|
||||
{
|
||||
gpiohs_set_pin(DCX_GPIONUM, GPIO_PV_LOW);
|
||||
}
|
||||
|
||||
static void set_dcx_data(void)
|
||||
{
|
||||
gpiohs_set_pin(DCX_GPIONUM, GPIO_PV_HIGH);
|
||||
}
|
||||
|
||||
#if BOARD_LICHEEDAN
|
||||
static void init_rst(void)
|
||||
{
|
||||
gpiohs_set_drive_mode(RST_GPIONUM, GPIO_DM_OUTPUT);
|
||||
gpiohs_set_pin(RST_GPIONUM, GPIO_PV_LOW);
|
||||
usleep(100000);
|
||||
gpiohs_set_pin(RST_GPIONUM, GPIO_PV_HIGH);
|
||||
usleep(100000);
|
||||
}
|
||||
#endif
|
||||
|
||||
void tft_hard_init(void)
|
||||
{
|
||||
init_dcx();
|
||||
spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
|
||||
#if BOARD_LICHEEDAN
|
||||
init_rst();
|
||||
spi_set_clk_rate(SPI_CHANNEL, 20000000);
|
||||
#else
|
||||
spi_set_clk_rate(SPI_CHANNEL, 25000000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tft_write_command(uint8_t cmd)
|
||||
{
|
||||
set_dcx_control();
|
||||
spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
|
||||
spi_init_non_standard(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/,
|
||||
SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
|
||||
spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT, (uint8_t *)(&cmd), 1,SPI_TRANS_CHAR);
|
||||
}
|
||||
|
||||
void tft_write_byte(uint8_t *data_buf, uint32_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 8, 0);
|
||||
spi_init_non_standard(SPI_CHANNEL, 8/*instrction length*/, 0/*address length*/, 0/*wait cycles*/,
|
||||
SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
|
||||
spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT, data_buf, length, SPI_TRANS_CHAR);
|
||||
}
|
||||
|
||||
void tft_write_half(uint16_t *data_buf, uint32_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 16, 0);
|
||||
spi_init_non_standard(SPI_CHANNEL, 16/*instrction length*/, 0/*address length*/, 0/*wait cycles*/,
|
||||
SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
|
||||
spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_SHORT);
|
||||
}
|
||||
|
||||
void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
|
||||
|
||||
spi_init_non_standard(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/,
|
||||
SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
|
||||
spi_send_data_normal_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT,data_buf, length, SPI_TRANS_INT);
|
||||
}
|
||||
|
||||
void tft_fill_data(uint32_t *data_buf, uint32_t length)
|
||||
{
|
||||
set_dcx_data();
|
||||
spi_init(SPI_CHANNEL, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
|
||||
spi_init_non_standard(SPI_CHANNEL, 0/*instrction length*/, 32/*address length*/, 0/*wait cycles*/,
|
||||
SPI_AITM_AS_FRAME_FORMAT/*spi address trans mode*/);
|
||||
spi_fill_data_dma(DMAC_CHANNEL0, SPI_CHANNEL, SPI_SLAVE_SELECT,data_buf, length);
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _NT35310_H_
|
||||
#define _NT35310_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* clang-format off */
|
||||
#define NO_OPERATION 0x00
|
||||
#define SOFTWARE_RESET 0x01
|
||||
#define READ_ID 0x04
|
||||
#define READ_STATUS 0x09
|
||||
#define READ_POWER_MODE 0x0A
|
||||
#define READ_MADCTL 0x0B
|
||||
#define READ_PIXEL_FORMAT 0x0C
|
||||
#define READ_IMAGE_FORMAT 0x0D
|
||||
#define READ_SIGNAL_MODE 0x0E
|
||||
#define READ_SELT_DIAG_RESULT 0x0F
|
||||
#define SLEEP_ON 0x10
|
||||
#define SLEEP_OFF 0x11
|
||||
#define PARTIAL_DISPALY_ON 0x12
|
||||
#define NORMAL_DISPALY_ON 0x13
|
||||
#define INVERSION_DISPALY_OFF 0x20
|
||||
#define INVERSION_DISPALY_ON 0x21
|
||||
#define GAMMA_SET 0x26
|
||||
#define DISPALY_OFF 0x28
|
||||
#define DISPALY_ON 0x29
|
||||
#define HORIZONTAL_ADDRESS_SET 0x2A
|
||||
#define VERTICAL_ADDRESS_SET 0x2B
|
||||
#define MEMORY_WRITE 0x2C
|
||||
#define COLOR_SET 0x2D
|
||||
#define MEMORY_READ 0x2E
|
||||
#define PARTIAL_AREA 0x30
|
||||
#define VERTICAL_SCROL_DEFINE 0x33
|
||||
#define TEAR_EFFECT_LINE_OFF 0x34
|
||||
#define TEAR_EFFECT_LINE_ON 0x35
|
||||
#define MEMORY_ACCESS_CTL 0x36
|
||||
#define VERTICAL_SCROL_S_ADD 0x37
|
||||
#define IDLE_MODE_OFF 0x38
|
||||
#define IDLE_MODE_ON 0x39
|
||||
#define PIXEL_FORMAT_SET 0x3A
|
||||
#define WRITE_MEMORY_CONTINUE 0x3C
|
||||
#define READ_MEMORY_CONTINUE 0x3E
|
||||
#define SET_TEAR_SCANLINE 0x44
|
||||
#define GET_SCANLINE 0x45
|
||||
#define WRITE_BRIGHTNESS 0x51
|
||||
#define READ_BRIGHTNESS 0x52
|
||||
#define WRITE_CTRL_DISPALY 0x53
|
||||
#define READ_CTRL_DISPALY 0x54
|
||||
#define WRITE_BRIGHTNESS_CTL 0x55
|
||||
#define READ_BRIGHTNESS_CTL 0x56
|
||||
#define WRITE_MIN_BRIGHTNESS 0x5E
|
||||
#define READ_MIN_BRIGHTNESS 0x5F
|
||||
#define READ_ID1 0xDA
|
||||
#define READ_ID2 0xDB
|
||||
#define READ_ID3 0xDC
|
||||
#define RGB_IF_SIGNAL_CTL 0xB0
|
||||
#define NORMAL_FRAME_CTL 0xB1
|
||||
#define IDLE_FRAME_CTL 0xB2
|
||||
#define PARTIAL_FRAME_CTL 0xB3
|
||||
#define INVERSION_CTL 0xB4
|
||||
#define BLANK_PORCH_CTL 0xB5
|
||||
#define DISPALY_FUNCTION_CTL 0xB6
|
||||
#define ENTRY_MODE_SET 0xB7
|
||||
#define BACKLIGHT_CTL1 0xB8
|
||||
#define BACKLIGHT_CTL2 0xB9
|
||||
#define BACKLIGHT_CTL3 0xBA
|
||||
#define BACKLIGHT_CTL4 0xBB
|
||||
#define BACKLIGHT_CTL5 0xBC
|
||||
#define BACKLIGHT_CTL7 0xBE
|
||||
#define BACKLIGHT_CTL8 0xBF
|
||||
#define POWER_CTL1 0xC0
|
||||
#define POWER_CTL2 0xC1
|
||||
#define VCOM_CTL1 0xC5
|
||||
#define VCOM_CTL2 0xC7
|
||||
#define NV_MEMORY_WRITE 0xD0
|
||||
#define NV_MEMORY_PROTECT_KEY 0xD1
|
||||
#define NV_MEMORY_STATUS_READ 0xD2
|
||||
#define READ_ID4 0xD3
|
||||
#define POSITIVE_GAMMA_CORRECT 0xE0
|
||||
#define NEGATIVE_GAMMA_CORRECT 0xE1
|
||||
#define DIGITAL_GAMMA_CTL1 0xE2
|
||||
#define DIGITAL_GAMMA_CTL2 0xE3
|
||||
#define INTERFACE_CTL 0xF6
|
||||
|
||||
#define DCX_GPIONUM (2)
|
||||
#define RST_GPIONUM (3)
|
||||
|
||||
#define SPI_CHANNEL 0
|
||||
#define SPI_SLAVE_SELECT 3
|
||||
/* clang-format on */
|
||||
|
||||
void tft_hard_init(void);
|
||||
void tft_write_command(uint8_t cmd);
|
||||
void tft_write_byte(uint8_t *data_buf, uint32_t length);
|
||||
void tft_write_half(uint16_t *data_buf, uint32_t length);
|
||||
void tft_write_word(uint32_t *data_buf, uint32_t length, uint32_t flag);
|
||||
void tft_fill_data(uint32_t *data_buf, uint32_t length);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "ov2640.h"
|
||||
#include "dvp.h"
|
||||
#include "plic.h"
|
||||
#include "board_config.h"
|
||||
|
||||
const uint8_t ov2640_config[][2]=
|
||||
{
|
||||
{0xff, 0x01},
|
||||
{0x12, 0x80},
|
||||
{0xff, 0x00},
|
||||
{0x2c, 0xff},
|
||||
{0x2e, 0xdf},
|
||||
{0xff, 0x01},
|
||||
{0x3c, 0x32},
|
||||
{0x11, 0x00},
|
||||
{0x09, 0x02},
|
||||
#if BOARD_LICHEEDAN
|
||||
{0x04, 0x88},//
|
||||
#else
|
||||
{0x04, 0x58},//
|
||||
#endif
|
||||
{0x13, 0xe5},
|
||||
{0x14, 0x48},
|
||||
{0x2c, 0x0c},
|
||||
{0x33, 0x78},
|
||||
{0x3a, 0x33},
|
||||
{0x3b, 0xfb},
|
||||
{0x3e, 0x00},
|
||||
{0x43, 0x11},
|
||||
{0x16, 0x10},
|
||||
{0x39, 0x92},
|
||||
{0x35, 0xda},
|
||||
{0x22, 0x1a},
|
||||
{0x37, 0xc3},
|
||||
{0x23, 0x00},
|
||||
{0x34, 0xc0},
|
||||
{0x36, 0x1a},
|
||||
{0x06, 0x88},
|
||||
{0x07, 0xc0},
|
||||
{0x0d, 0x87},
|
||||
{0x0e, 0x41},
|
||||
{0x4c, 0x00},
|
||||
{0x48, 0x00},
|
||||
{0x5b, 0x00},
|
||||
{0x42, 0x03},
|
||||
{0x4a, 0x81},
|
||||
{0x21, 0x99},
|
||||
{0x24, 0x40},
|
||||
{0x25, 0x38},
|
||||
{0x26, 0x82},
|
||||
{0x5c, 0x00},
|
||||
{0x63, 0x00},
|
||||
{0x46, 0x22},
|
||||
{0x0c, 0x3c},
|
||||
{0x61, 0x70},
|
||||
{0x62, 0x80},
|
||||
{0x7c, 0x05},
|
||||
{0x20, 0x80},
|
||||
{0x28, 0x30},
|
||||
{0x6c, 0x00},
|
||||
{0x6d, 0x80},
|
||||
{0x6e, 0x00},
|
||||
{0x70, 0x02},
|
||||
{0x71, 0x94},
|
||||
{0x73, 0xc1},
|
||||
{0x3d, 0x34},
|
||||
{0x5a, 0x57},
|
||||
{0x12, 0x40},
|
||||
{0x17, 0x11},
|
||||
{0x18, 0x43},
|
||||
{0x19, 0x00},
|
||||
{0x1a, 0x4b},
|
||||
{0x32, 0x09},
|
||||
{0x37, 0xc0},
|
||||
{0x4f, 0xca},
|
||||
{0x50, 0xa8},
|
||||
{0x5a, 0x23},
|
||||
{0x6d, 0x00},
|
||||
{0x3d, 0x38},
|
||||
{0xff, 0x00},
|
||||
{0xe5, 0x7f},
|
||||
{0xf9, 0xc0},
|
||||
{0x41, 0x24},
|
||||
{0xe0, 0x14},
|
||||
{0x76, 0xff},
|
||||
{0x33, 0xa0},
|
||||
{0x42, 0x20},
|
||||
{0x43, 0x18},
|
||||
{0x4c, 0x00},
|
||||
{0x87, 0xd5},
|
||||
{0x88, 0x3f},
|
||||
{0xd7, 0x03},
|
||||
{0xd9, 0x10},
|
||||
{0xd3, 0x82},
|
||||
{0xc8, 0x08},
|
||||
{0xc9, 0x80},
|
||||
{0x7c, 0x00},
|
||||
{0x7d, 0x00},
|
||||
{0x7c, 0x03},
|
||||
{0x7d, 0x48},
|
||||
{0x7d, 0x48},
|
||||
{0x7c, 0x08},
|
||||
{0x7d, 0x20},
|
||||
{0x7d, 0x10},
|
||||
{0x7d, 0x0e},
|
||||
{0x90, 0x00},
|
||||
{0x91, 0x0e},
|
||||
{0x91, 0x1a},
|
||||
{0x91, 0x31},
|
||||
{0x91, 0x5a},
|
||||
{0x91, 0x69},
|
||||
{0x91, 0x75},
|
||||
{0x91, 0x7e},
|
||||
{0x91, 0x88},
|
||||
{0x91, 0x8f},
|
||||
{0x91, 0x96},
|
||||
{0x91, 0xa3},
|
||||
{0x91, 0xaf},
|
||||
{0x91, 0xc4},
|
||||
{0x91, 0xd7},
|
||||
{0x91, 0xe8},
|
||||
{0x91, 0x20},
|
||||
{0x92, 0x00},
|
||||
{0x93, 0x06},
|
||||
{0x93, 0xe3},
|
||||
{0x93, 0x05},
|
||||
{0x93, 0x05},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x04},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x93, 0x00},
|
||||
{0x96, 0x00},
|
||||
{0x97, 0x08},
|
||||
{0x97, 0x19},
|
||||
{0x97, 0x02},
|
||||
{0x97, 0x0c},
|
||||
{0x97, 0x24},
|
||||
{0x97, 0x30},
|
||||
{0x97, 0x28},
|
||||
{0x97, 0x26},
|
||||
{0x97, 0x02},
|
||||
{0x97, 0x98},
|
||||
{0x97, 0x80},
|
||||
{0x97, 0x00},
|
||||
{0x97, 0x00},
|
||||
{0xc3, 0xed},
|
||||
{0xa4, 0x00},
|
||||
{0xa8, 0x00},
|
||||
{0xc5, 0x11},
|
||||
{0xc6, 0x51},
|
||||
{0xbf, 0x80},
|
||||
{0xc7, 0x10},
|
||||
{0xb6, 0x66},
|
||||
{0xb8, 0xa5},
|
||||
{0xb7, 0x64},
|
||||
{0xb9, 0x7c},
|
||||
{0xb3, 0xaf},
|
||||
{0xb4, 0x97},
|
||||
{0xb5, 0xff},
|
||||
{0xb0, 0xc5},
|
||||
{0xb1, 0x94},
|
||||
{0xb2, 0x0f},
|
||||
{0xc4, 0x5c},
|
||||
{0xc0, 0x64},
|
||||
{0xc1, 0x4b},
|
||||
{0x8c, 0x00},
|
||||
{0x86, 0x3d},
|
||||
{0x50, 0x00},
|
||||
{0x51, 0xc8},
|
||||
{0x52, 0x96},
|
||||
{0x53, 0x00},
|
||||
{0x54, 0x00},
|
||||
{0x55, 0x00},
|
||||
{0x5a, 0xc8},
|
||||
{0x5b, 0x96},
|
||||
{0x5c, 0x00},
|
||||
{0xd3, 0x02},
|
||||
{0xc3, 0xed},
|
||||
{0x7f, 0x00},
|
||||
{0xda, 0x08},//
|
||||
{0xe5, 0x1f},
|
||||
{0xe1, 0x67},
|
||||
{0xe0, 0x00},
|
||||
{0xdd, 0x7f},
|
||||
{0x05, 0x00},
|
||||
{0xff, 0x00},
|
||||
{0xe0, 0x04},
|
||||
{0x5a, 0x50},
|
||||
{0x5b, 0x3c},
|
||||
{0x5c, 0x00},
|
||||
{0xe0, 0x00},
|
||||
{0x00, 0x00}
|
||||
};
|
||||
|
||||
int ov2640_init(void)
|
||||
{
|
||||
uint16_t v_manuf_id;
|
||||
uint16_t v_device_id;
|
||||
ov2640_read_id(&v_manuf_id, &v_device_id);
|
||||
printf("manuf_id:0x%04x,device_id:0x%04x\n", v_manuf_id, v_device_id);
|
||||
uint16_t index = 0;
|
||||
for (index = 0; ov2640_config[index][0]; index++)
|
||||
dvp_sccb_send_data(OV2640_ADDR, ov2640_config[index][0], ov2640_config[index][1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id)
|
||||
{
|
||||
dvp_sccb_send_data(OV2640_ADDR, 0xFF, 0x01);
|
||||
*manuf_id = (dvp_sccb_receive_data(OV2640_ADDR, 0x1C) << 8) | dvp_sccb_receive_data(OV2640_ADDR, 0x1D);
|
||||
*device_id = (dvp_sccb_receive_data(OV2640_ADDR, 0x0A) << 8) | dvp_sccb_receive_data(OV2640_ADDR, 0x0B);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,29 +1,26 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <datatypes.h>
|
||||
#include <xtensor/xstorage.hpp>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace neutral
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _OV2640_H
|
||||
#define _OV2640_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define OV2640_ADDR 0x60
|
||||
|
||||
int ov2640_init(void);
|
||||
int ov2640_read_id(uint16_t *manuf_id, uint16_t *device_id);
|
||||
|
||||
#endif /* _OV2640_H */
|
||||
|
|
@ -0,0 +1,310 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "ov5640.h"
|
||||
#include "ov5640cfg.h"
|
||||
#include "ov5640af.h"
|
||||
#include "dvp.h"
|
||||
|
||||
static void hal_delay(uint32_t delay)
|
||||
{
|
||||
usleep(delay * 1000);
|
||||
}
|
||||
|
||||
static void ov5640_wr_reg(uint16_t reg,uint8_t data)
|
||||
{
|
||||
dvp_sccb_send_data(OV5640_ADDR, reg, data);
|
||||
}
|
||||
|
||||
static uint8_t ov5640_rd_reg(uint16_t reg)
|
||||
{
|
||||
return dvp_sccb_receive_data(OV5640_ADDR, reg);
|
||||
}
|
||||
|
||||
uint8_t ov5640_init(void)
|
||||
{
|
||||
uint16_t i = 0;
|
||||
uint16_t reg = 0;
|
||||
|
||||
reg = ov5640_rd_reg(OV5640_CHIPIDH);
|
||||
reg <<= 8;
|
||||
reg |= ov5640_rd_reg(OV5640_CHIPIDL);
|
||||
printf("ID: %X \r\n", reg);
|
||||
if(reg != OV5640_ID)
|
||||
{
|
||||
printf("ID: %d \r\n", reg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ov5640_wr_reg(0x3103,0X11); /*system clock from pad, bit[1]*/
|
||||
ov5640_wr_reg(0X3008,0X82);
|
||||
hal_delay(10);
|
||||
|
||||
for(i = 0; i<sizeof(ov5640_init_reg_tbl) / 4; i++)
|
||||
{
|
||||
ov5640_wr_reg(ov5640_init_reg_tbl[i][0], ov5640_init_reg_tbl[i][1]);
|
||||
}
|
||||
|
||||
hal_delay(50);
|
||||
/* Test for flash light*/
|
||||
ov5640_flash_lamp(1);
|
||||
hal_delay(50);
|
||||
ov5640_flash_lamp(0);
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void ov5640_flash_lamp(uint8_t sw)
|
||||
{
|
||||
ov5640_wr_reg(0x3016, 0X02);
|
||||
ov5640_wr_reg(0x301C, 0X02);
|
||||
if(sw)
|
||||
ov5640_wr_reg(0X3019, 0X02);
|
||||
else
|
||||
ov5640_wr_reg(0X3019, 0X00);
|
||||
}
|
||||
|
||||
const static uint8_t OV5640_EXPOSURE_TBL[7][6]=
|
||||
{
|
||||
0x10,0x08,0x10,0x08,0x20,0x10,//-3
|
||||
0x20,0x18,0x41,0x20,0x18,0x10,//-2
|
||||
0x30,0x28,0x61,0x30,0x28,0x10,//-1
|
||||
0x38,0x30,0x61,0x38,0x30,0x10,//0
|
||||
0x40,0x38,0x71,0x40,0x38,0x10,//+1
|
||||
0x50,0x48,0x90,0x50,0x48,0x20,//+2
|
||||
0x60,0x58,0xa0,0x60,0x58,0x20,//+3
|
||||
};
|
||||
|
||||
//exposure: 0 - 6,
|
||||
void OV5640_Exposure(uint8_t exposure)
|
||||
{
|
||||
ov5640_wr_reg(0x3212,0x03); //start group 3
|
||||
ov5640_wr_reg(0x3a0f,OV5640_EXPOSURE_TBL[exposure][0]);
|
||||
ov5640_wr_reg(0x3a10,OV5640_EXPOSURE_TBL[exposure][1]);
|
||||
ov5640_wr_reg(0x3a1b,OV5640_EXPOSURE_TBL[exposure][2]);
|
||||
ov5640_wr_reg(0x3a1e,OV5640_EXPOSURE_TBL[exposure][3]);
|
||||
ov5640_wr_reg(0x3a11,OV5640_EXPOSURE_TBL[exposure][4]);
|
||||
ov5640_wr_reg(0x3a1f,OV5640_EXPOSURE_TBL[exposure][5]);
|
||||
ov5640_wr_reg(0x3212,0x13); //end group 3
|
||||
ov5640_wr_reg(0x3212,0xa3); //launch group 3
|
||||
}
|
||||
|
||||
const static uint8_t OV5640_LIGHTMODE_TBL[5][7]=
|
||||
{
|
||||
0x04,0X00,0X04,0X00,0X04,0X00,0X00,//Auto
|
||||
0x06,0X1C,0X04,0X00,0X04,0XF3,0X01,//Sunny
|
||||
0x05,0X48,0X04,0X00,0X07,0XCF,0X01,//Office
|
||||
0x06,0X48,0X04,0X00,0X04,0XD3,0X01,//Cloudy
|
||||
0x04,0X10,0X04,0X00,0X08,0X40,0X01,//Home
|
||||
};
|
||||
|
||||
// light mode:
|
||||
// 0: auto
|
||||
// 1: sunny
|
||||
// 2: office
|
||||
// 3: cloudy
|
||||
// 4: home
|
||||
void OV5640_Light_Mode(uint8_t mode)
|
||||
{
|
||||
uint8_t i;
|
||||
ov5640_wr_reg(0x3212,0x03); //start group 3
|
||||
for(i=0;i<7;i++)ov5640_wr_reg(0x3400+i,OV5640_LIGHTMODE_TBL[mode][i]);
|
||||
ov5640_wr_reg(0x3212,0x13); //end group 3
|
||||
ov5640_wr_reg(0x3212,0xa3); //launch group 3
|
||||
}
|
||||
|
||||
const static uint8_t OV5640_SATURATION_TBL[7][6]=
|
||||
{
|
||||
0X0C,0x30,0X3D,0X3E,0X3D,0X01,//-3
|
||||
0X10,0x3D,0X4D,0X4E,0X4D,0X01,//-2
|
||||
0X15,0x52,0X66,0X68,0X66,0X02,//-1
|
||||
0X1A,0x66,0X80,0X82,0X80,0X02,//+0
|
||||
0X1F,0x7A,0X9A,0X9C,0X9A,0X02,//+1
|
||||
0X24,0x8F,0XB3,0XB6,0XB3,0X03,//+2
|
||||
0X2B,0xAB,0XD6,0XDA,0XD6,0X04,//+3
|
||||
};
|
||||
|
||||
|
||||
// Color Saturation:
|
||||
// sat: 0 - 6
|
||||
void OV5640_Color_Saturation(uint8_t sat)
|
||||
{
|
||||
uint8_t i;
|
||||
ov5640_wr_reg(0x3212,0x03); //start group 3
|
||||
ov5640_wr_reg(0x5381,0x1c);
|
||||
ov5640_wr_reg(0x5382,0x5a);
|
||||
ov5640_wr_reg(0x5383,0x06);
|
||||
for(i=0;i<6;i++) ov5640_wr_reg(0x5384+i,OV5640_SATURATION_TBL[sat][i]);
|
||||
ov5640_wr_reg(0x538b, 0x98);
|
||||
ov5640_wr_reg(0x538a, 0x01);
|
||||
ov5640_wr_reg(0x3212, 0x13); //end group 3
|
||||
ov5640_wr_reg(0x3212, 0xa3); //launch group 3
|
||||
}
|
||||
|
||||
//Brightness
|
||||
// bright: 0 - 8
|
||||
void OV5640_Brightness(uint8_t bright)
|
||||
{
|
||||
uint8_t brtval;
|
||||
if(bright<4)brtval=4-bright;
|
||||
else brtval=bright-4;
|
||||
ov5640_wr_reg(0x3212,0x03); //start group 3
|
||||
ov5640_wr_reg(0x5587,brtval<<4);
|
||||
if(bright<4)ov5640_wr_reg(0x5588,0x09);
|
||||
else ov5640_wr_reg(0x5588,0x01);
|
||||
ov5640_wr_reg(0x3212,0x13); //end group 3
|
||||
ov5640_wr_reg(0x3212,0xa3); //launch group 3
|
||||
}
|
||||
|
||||
//Contrast:
|
||||
// contrast: 0 - 6
|
||||
void OV5640_Contrast(uint8_t contrast)
|
||||
{
|
||||
uint8_t reg0val=0X00;
|
||||
uint8_t reg1val=0X20;
|
||||
switch(contrast)
|
||||
{
|
||||
case 0://-3
|
||||
reg1val=reg0val=0X14;
|
||||
break;
|
||||
case 1://-2
|
||||
reg1val=reg0val=0X18;
|
||||
break;
|
||||
case 2://-1
|
||||
reg1val=reg0val=0X1C;
|
||||
break;
|
||||
case 4://1
|
||||
reg0val=0X10;
|
||||
reg1val=0X24;
|
||||
break;
|
||||
case 5://2
|
||||
reg0val=0X18;
|
||||
reg1val=0X28;
|
||||
break;
|
||||
case 6://3
|
||||
reg0val=0X1C;
|
||||
reg1val=0X2C;
|
||||
break;
|
||||
}
|
||||
ov5640_wr_reg(0x3212,0x03); //start group 3
|
||||
ov5640_wr_reg(0x5585,reg0val);
|
||||
ov5640_wr_reg(0x5586,reg1val);
|
||||
ov5640_wr_reg(0x3212,0x13); //end group 3
|
||||
ov5640_wr_reg(0x3212,0xa3); //launch group 3
|
||||
}
|
||||
// Sharpness:
|
||||
// sharp: 0 - 33 (0: close , 33: auto , other: Sharpness)
|
||||
|
||||
void OV5640_Sharpness(uint8_t sharp)
|
||||
{
|
||||
if(sharp<33)
|
||||
{
|
||||
ov5640_wr_reg(0x5308,0x65);
|
||||
ov5640_wr_reg(0x5302,sharp);
|
||||
}else // auto
|
||||
{
|
||||
ov5640_wr_reg(0x5308,0x25);
|
||||
ov5640_wr_reg(0x5300,0x08);
|
||||
ov5640_wr_reg(0x5301,0x30);
|
||||
ov5640_wr_reg(0x5302,0x10);
|
||||
ov5640_wr_reg(0x5303,0x00);
|
||||
ov5640_wr_reg(0x5309,0x08);
|
||||
ov5640_wr_reg(0x530a,0x30);
|
||||
ov5640_wr_reg(0x530b,0x04);
|
||||
ov5640_wr_reg(0x530c,0x06);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const static uint8_t OV5640_EFFECTS_TBL[7][3]=
|
||||
{
|
||||
0X06,0x40,0X10, // normal
|
||||
0X1E,0xA0,0X40,
|
||||
0X1E,0x80,0XC0,
|
||||
0X1E,0x80,0X80,
|
||||
0X1E,0x40,0XA0,
|
||||
0X40,0x40,0X10,
|
||||
0X1E,0x60,0X60,
|
||||
};
|
||||
|
||||
void OV5640_Special_Effects(uint8_t eft)
|
||||
{
|
||||
ov5640_wr_reg(0x3212,0x03); //start group 3
|
||||
ov5640_wr_reg(0x5580,OV5640_EFFECTS_TBL[eft][0]);
|
||||
ov5640_wr_reg(0x5583,OV5640_EFFECTS_TBL[eft][1]);// sat U
|
||||
ov5640_wr_reg(0x5584,OV5640_EFFECTS_TBL[eft][2]);// sat V
|
||||
ov5640_wr_reg(0x5003,0x08);
|
||||
ov5640_wr_reg(0x3212,0x13); //end group 3
|
||||
ov5640_wr_reg(0x3212,0xa3); //launch group 3
|
||||
}
|
||||
|
||||
uint8_t OV5640_Focus_Init(void)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t addr=0x8000;
|
||||
uint8_t state=0x8F;
|
||||
ov5640_wr_reg(0x3000, 0x20); //reset
|
||||
for(i=0;i<sizeof(OV5640_AF_Config);i++)
|
||||
{
|
||||
ov5640_wr_reg(addr,OV5640_AF_Config[i]);
|
||||
addr++;
|
||||
}
|
||||
ov5640_wr_reg(0x3022,0x00);
|
||||
ov5640_wr_reg(0x3023,0x00);
|
||||
ov5640_wr_reg(0x3024,0x00);
|
||||
ov5640_wr_reg(0x3025,0x00);
|
||||
ov5640_wr_reg(0x3026,0x00);
|
||||
ov5640_wr_reg(0x3027,0x00);
|
||||
ov5640_wr_reg(0x3028,0x00);
|
||||
ov5640_wr_reg(0x3029,0x7f);
|
||||
ov5640_wr_reg(0x3000,0x00);
|
||||
i=0;
|
||||
do
|
||||
{
|
||||
state=ov5640_rd_reg(0x3029);
|
||||
hal_delay(5);
|
||||
i++;
|
||||
if(i>1000)return 1;
|
||||
}while(state!=0x70);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t OV5640_Auto_Focus(void)
|
||||
{
|
||||
uint8_t temp=0;
|
||||
uint16_t retry=0;
|
||||
ov5640_wr_reg(0x3023,0x01);
|
||||
ov5640_wr_reg(0x3022,0x08);
|
||||
do
|
||||
{
|
||||
temp=ov5640_rd_reg(0x3023);
|
||||
retry++;
|
||||
if(retry>1000)return 2;
|
||||
hal_delay(5);
|
||||
} while(temp!=0x00);
|
||||
ov5640_wr_reg(0x3023,0x01);
|
||||
ov5640_wr_reg(0x3022,0x04);
|
||||
retry=0;
|
||||
do
|
||||
{
|
||||
temp=ov5640_rd_reg(0x3023);
|
||||
retry++;
|
||||
if(retry>1000)return 2;
|
||||
hal_delay(5);
|
||||
}while(temp!=0x00);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _OV5640_H
|
||||
#define _OV5640_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define OV5640_ID 0X5640
|
||||
#define OV5640_ADDR 0X78
|
||||
#define OV5640_CHIPIDH 0X300A
|
||||
#define OV5640_CHIPIDL 0X300B
|
||||
|
||||
#define XSIZE 320
|
||||
#define YSIZE 240
|
||||
#define LCD_GRAM_ADDRESS 0x60020000
|
||||
|
||||
#define QQVGA_160_120 0
|
||||
#define QCIF_176_144 1
|
||||
#define QVGA_320_240 2
|
||||
#define WQVGA_400_240 3
|
||||
#define CIF_352_288 4
|
||||
|
||||
#define jpeg_buf_size (30*1024)
|
||||
|
||||
uint8_t ov5640_init(void);
|
||||
void ov5640_flash_lamp(uint8_t sw);
|
||||
void OV5640_Brightness(uint8_t bright);
|
||||
void OV5640_Exposure(uint8_t exposure);
|
||||
void OV5640_Light_Mode(uint8_t mode);
|
||||
void OV5640_Color_Saturation(uint8_t sat);
|
||||
void OV5640_Brightness(uint8_t bright);
|
||||
void OV5640_Contrast(uint8_t contrast);
|
||||
void OV5640_Sharpness(uint8_t sharp);
|
||||
void OV5640_Special_Effects(uint8_t eft);
|
||||
uint8_t OV5640_Focus_Init(void);
|
||||
uint8_t OV5640_Auto_Focus(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
#ifndef _OV5640AF_H
|
||||
#define _OV5640AF_H
|
||||
|
||||
|
||||
// auto focus config
|
||||
const unsigned char OV5640_AF_Config[] =
|
||||
{
|
||||
0x02, 0x0f, 0xd6, 0x02, 0x0a, 0x39, 0xc2, 0x01, 0x22, 0x22, 0x00, 0x02, 0x0f, 0xb2, 0xe5, 0x1f, //0x8000,
|
||||
0x70, 0x72, 0xf5, 0x1e, 0xd2, 0x35, 0xff, 0xef, 0x25, 0xe0, 0x24, 0x4e, 0xf8, 0xe4, 0xf6, 0x08, //0x8010,
|
||||
0xf6, 0x0f, 0xbf, 0x34, 0xf2, 0x90, 0x0e, 0x93, 0xe4, 0x93, 0xff, 0xe5, 0x4b, 0xc3, 0x9f, 0x50, //0x8020,
|
||||
0x04, 0x7f, 0x05, 0x80, 0x02, 0x7f, 0xfb, 0x78, 0xbd, 0xa6, 0x07, 0x12, 0x0f, 0x04, 0x40, 0x04, //0x8030,
|
||||
0x7f, 0x03, 0x80, 0x02, 0x7f, 0x30, 0x78, 0xbc, 0xa6, 0x07, 0xe6, 0x18, 0xf6, 0x08, 0xe6, 0x78, //0x8040,
|
||||
0xb9, 0xf6, 0x78, 0xbc, 0xe6, 0x78, 0xba, 0xf6, 0x78, 0xbf, 0x76, 0x33, 0xe4, 0x08, 0xf6, 0x78, //0x8050,
|
||||
0xb8, 0x76, 0x01, 0x75, 0x4a, 0x02, 0x78, 0xb6, 0xf6, 0x08, 0xf6, 0x74, 0xff, 0x78, 0xc1, 0xf6, //0x8060,
|
||||
0x08, 0xf6, 0x75, 0x1f, 0x01, 0x78, 0xbc, 0xe6, 0x75, 0xf0, 0x05, 0xa4, 0xf5, 0x4b, 0x12, 0x0a, //0x8070,
|
||||
0xff, 0xc2, 0x37, 0x22, 0x78, 0xb8, 0xe6, 0xd3, 0x94, 0x00, 0x40, 0x02, 0x16, 0x22, 0xe5, 0x1f, //0x8080,
|
||||
0xb4, 0x05, 0x23, 0xe4, 0xf5, 0x1f, 0xc2, 0x01, 0x78, 0xb6, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x78, //0x8090,
|
||||
0x4e, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xa2, 0x37, 0xe4, 0x33, 0xf5, 0x3c, 0x90, 0x30, 0x28, 0xf0, //0x80a0,
|
||||
0x75, 0x1e, 0x10, 0xd2, 0x35, 0x22, 0xe5, 0x4b, 0x75, 0xf0, 0x05, 0x84, 0x78, 0xbc, 0xf6, 0x90, //0x80b0,
|
||||
0x0e, 0x8c, 0xe4, 0x93, 0xff, 0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x78, //0x80c0,
|
||||
0xbc, 0xe6, 0x25, 0xe0, 0x24, 0x4e, 0xf8, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0xef, 0x12, 0x0f, 0x0b, //0x80d0,
|
||||
0xd3, 0x78, 0xb7, 0x96, 0xee, 0x18, 0x96, 0x40, 0x0d, 0x78, 0xbc, 0xe6, 0x78, 0xb9, 0xf6, 0x78, //0x80e0,
|
||||
0xb6, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x8c, 0xe4, 0x93, 0x12, 0x0f, 0x0b, 0xc3, 0x78, //0x80f0,
|
||||
0xc2, 0x96, 0xee, 0x18, 0x96, 0x50, 0x0d, 0x78, 0xbc, 0xe6, 0x78, 0xba, 0xf6, 0x78, 0xc1, 0xa6, //0x8100,
|
||||
0x06, 0x08, 0xa6, 0x07, 0x78, 0xb6, 0xe6, 0xfe, 0x08, 0xe6, 0xc3, 0x78, 0xc2, 0x96, 0xff, 0xee, //0x8110,
|
||||
0x18, 0x96, 0x78, 0xc3, 0xf6, 0x08, 0xa6, 0x07, 0x90, 0x0e, 0x95, 0xe4, 0x18, 0x12, 0x0e, 0xe9, //0x8120,
|
||||
0x40, 0x02, 0xd2, 0x37, 0x78, 0xbc, 0xe6, 0x08, 0x26, 0x08, 0xf6, 0xe5, 0x1f, 0x64, 0x01, 0x70, //0x8130,
|
||||
0x4a, 0xe6, 0xc3, 0x78, 0xc0, 0x12, 0x0e, 0xdf, 0x40, 0x05, 0x12, 0x0e, 0xda, 0x40, 0x39, 0x12, //0x8140,
|
||||
0x0f, 0x02, 0x40, 0x04, 0x7f, 0xfe, 0x80, 0x02, 0x7f, 0x02, 0x78, 0xbd, 0xa6, 0x07, 0x78, 0xb9, //0x8150,
|
||||
0xe6, 0x24, 0x03, 0x78, 0xbf, 0xf6, 0x78, 0xb9, 0xe6, 0x24, 0xfd, 0x78, 0xc0, 0xf6, 0x12, 0x0f, //0x8160,
|
||||
0x02, 0x40, 0x06, 0x78, 0xc0, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbf, 0xe6, 0xff, 0x78, 0xbe, 0xa6, //0x8170,
|
||||
0x07, 0x75, 0x1f, 0x02, 0x78, 0xb8, 0x76, 0x01, 0x02, 0x02, 0x4a, 0xe5, 0x1f, 0x64, 0x02, 0x60, //0x8180,
|
||||
0x03, 0x02, 0x02, 0x2a, 0x78, 0xbe, 0xe6, 0xff, 0xc3, 0x78, 0xc0, 0x12, 0x0e, 0xe0, 0x40, 0x08, //0x8190,
|
||||
0x12, 0x0e, 0xda, 0x50, 0x03, 0x02, 0x02, 0x28, 0x12, 0x0f, 0x02, 0x40, 0x04, 0x7f, 0xff, 0x80, //0x81a0,
|
||||
0x02, 0x7f, 0x01, 0x78, 0xbd, 0xa6, 0x07, 0x78, 0xb9, 0xe6, 0x04, 0x78, 0xbf, 0xf6, 0x78, 0xb9, //0x81b0,
|
||||
0xe6, 0x14, 0x78, 0xc0, 0xf6, 0x18, 0x12, 0x0f, 0x04, 0x40, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, //0x81c0,
|
||||
0x00, 0x78, 0xbf, 0xa6, 0x07, 0xd3, 0x08, 0xe6, 0x64, 0x80, 0x94, 0x80, 0x40, 0x04, 0xe6, 0xff, //0x81d0,
|
||||
0x80, 0x02, 0x7f, 0x00, 0x78, 0xc0, 0xa6, 0x07, 0xc3, 0x18, 0xe6, 0x64, 0x80, 0x94, 0xb3, 0x50, //0x81e0,
|
||||
0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xbf, 0xa6, 0x07, 0xc3, 0x08, 0xe6, 0x64, 0x80, //0x81f0,
|
||||
0x94, 0xb3, 0x50, 0x04, 0xe6, 0xff, 0x80, 0x02, 0x7f, 0x33, 0x78, 0xc0, 0xa6, 0x07, 0x12, 0x0f, //0x8200,
|
||||
0x02, 0x40, 0x06, 0x78, 0xc0, 0xe6, 0xff, 0x80, 0x04, 0x78, 0xbf, 0xe6, 0xff, 0x78, 0xbe, 0xa6, //0x8210,
|
||||
0x07, 0x75, 0x1f, 0x03, 0x78, 0xb8, 0x76, 0x01, 0x80, 0x20, 0xe5, 0x1f, 0x64, 0x03, 0x70, 0x26, //0x8220,
|
||||
0x78, 0xbe, 0xe6, 0xff, 0xc3, 0x78, 0xc0, 0x12, 0x0e, 0xe0, 0x40, 0x05, 0x12, 0x0e, 0xda, 0x40, //0x8230,
|
||||
0x09, 0x78, 0xb9, 0xe6, 0x78, 0xbe, 0xf6, 0x75, 0x1f, 0x04, 0x78, 0xbe, 0xe6, 0x75, 0xf0, 0x05, //0x8240,
|
||||
0xa4, 0xf5, 0x4b, 0x02, 0x0a, 0xff, 0xe5, 0x1f, 0xb4, 0x04, 0x10, 0x90, 0x0e, 0x94, 0xe4, 0x78, //0x8250,
|
||||
0xc3, 0x12, 0x0e, 0xe9, 0x40, 0x02, 0xd2, 0x37, 0x75, 0x1f, 0x05, 0x22, 0x30, 0x01, 0x03, 0x02, //0x8260,
|
||||
0x04, 0xc0, 0x30, 0x02, 0x03, 0x02, 0x04, 0xc0, 0x90, 0x51, 0xa5, 0xe0, 0x78, 0x93, 0xf6, 0xa3, //0x8270,
|
||||
0xe0, 0x08, 0xf6, 0xa3, 0xe0, 0x08, 0xf6, 0xe5, 0x1f, 0x70, 0x3c, 0x75, 0x1e, 0x20, 0xd2, 0x35, //0x8280,
|
||||
0x12, 0x0c, 0x7a, 0x78, 0x7e, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x8b, 0xa6, 0x09, 0x18, 0x76, //0x8290,
|
||||
0x01, 0x12, 0x0c, 0x5b, 0x78, 0x4e, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x8b, 0xe6, 0x78, 0x6e, //0x82a0,
|
||||
0xf6, 0x75, 0x1f, 0x01, 0x78, 0x93, 0xe6, 0x78, 0x90, 0xf6, 0x78, 0x94, 0xe6, 0x78, 0x91, 0xf6, //0x82b0,
|
||||
0x78, 0x95, 0xe6, 0x78, 0x92, 0xf6, 0x22, 0x79, 0x90, 0xe7, 0xd3, 0x78, 0x93, 0x96, 0x40, 0x05, //0x82c0,
|
||||
0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0x93, 0xe7, 0x78, 0x90, 0x96, 0xff, 0x78, 0x88, 0x76, //0x82d0,
|
||||
0x00, 0x08, 0xa6, 0x07, 0x79, 0x91, 0xe7, 0xd3, 0x78, 0x94, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, //0x82e0,
|
||||
0x80, 0x08, 0xc3, 0x79, 0x94, 0xe7, 0x78, 0x91, 0x96, 0xff, 0x12, 0x0c, 0x8e, 0x79, 0x92, 0xe7, //0x82f0,
|
||||
0xd3, 0x78, 0x95, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, 0x08, 0xc3, 0x79, 0x95, 0xe7, 0x78, //0x8300,
|
||||
0x92, 0x96, 0xff, 0x12, 0x0c, 0x8e, 0x12, 0x0c, 0x5b, 0x78, 0x8a, 0xe6, 0x25, 0xe0, 0x24, 0x4e, //0x8310,
|
||||
0xf8, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x78, 0x8a, 0xe6, 0x24, 0x6e, 0xf8, 0xa6, 0x09, 0x78, 0x8a, //0x8320,
|
||||
0xe6, 0x24, 0x01, 0xff, 0xe4, 0x33, 0xfe, 0xd3, 0xef, 0x94, 0x0f, 0xee, 0x64, 0x80, 0x94, 0x80, //0x8330,
|
||||
0x40, 0x04, 0x7f, 0x00, 0x80, 0x05, 0x78, 0x8a, 0xe6, 0x04, 0xff, 0x78, 0x8a, 0xa6, 0x07, 0xe5, //0x8340,
|
||||
0x1f, 0xb4, 0x01, 0x0a, 0xe6, 0x60, 0x03, 0x02, 0x04, 0xc0, 0x75, 0x1f, 0x02, 0x22, 0x12, 0x0c, //0x8350,
|
||||
0x7a, 0x78, 0x80, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0x12, 0x0c, 0x7a, 0x78, 0x82, 0xa6, 0x06, 0x08, //0x8360,
|
||||
0xa6, 0x07, 0x78, 0x6e, 0xe6, 0x78, 0x8c, 0xf6, 0x78, 0x6e, 0xe6, 0x78, 0x8d, 0xf6, 0x7f, 0x01, //0x8370,
|
||||
0xef, 0x25, 0xe0, 0x24, 0x4f, 0xf9, 0xc3, 0x78, 0x81, 0xe6, 0x97, 0x18, 0xe6, 0x19, 0x97, 0x50, //0x8380,
|
||||
0x0a, 0x12, 0x0c, 0x82, 0x78, 0x80, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 0x6e, 0x2f, 0xf9, 0x78, //0x8390,
|
||||
0x8c, 0xe6, 0xc3, 0x97, 0x50, 0x08, 0x74, 0x6e, 0x2f, 0xf8, 0xe6, 0x78, 0x8c, 0xf6, 0xef, 0x25, //0x83a0,
|
||||
0xe0, 0x24, 0x4f, 0xf9, 0xd3, 0x78, 0x83, 0xe6, 0x97, 0x18, 0xe6, 0x19, 0x97, 0x40, 0x0a, 0x12, //0x83b0,
|
||||
0x0c, 0x82, 0x78, 0x82, 0xa6, 0x04, 0x08, 0xa6, 0x05, 0x74, 0x6e, 0x2f, 0xf9, 0x78, 0x8d, 0xe6, //0x83c0,
|
||||
0xd3, 0x97, 0x40, 0x08, 0x74, 0x6e, 0x2f, 0xf8, 0xe6, 0x78, 0x8d, 0xf6, 0x0f, 0xef, 0x64, 0x10, //0x83d0,
|
||||
0x70, 0x9e, 0xc3, 0x79, 0x81, 0xe7, 0x78, 0x83, 0x96, 0xff, 0x19, 0xe7, 0x18, 0x96, 0x78, 0x84, //0x83e0,
|
||||
0xf6, 0x08, 0xa6, 0x07, 0xc3, 0x79, 0x8c, 0xe7, 0x78, 0x8d, 0x96, 0x08, 0xf6, 0xd3, 0x79, 0x81, //0x83f0,
|
||||
0xe7, 0x78, 0x7f, 0x96, 0x19, 0xe7, 0x18, 0x96, 0x40, 0x05, 0x09, 0xe7, 0x08, 0x80, 0x06, 0xc3, //0x8400,
|
||||
0x79, 0x7f, 0xe7, 0x78, 0x81, 0x96, 0xff, 0x19, 0xe7, 0x18, 0x96, 0xfe, 0x78, 0x86, 0xa6, 0x06, //0x8410,
|
||||
0x08, 0xa6, 0x07, 0x79, 0x8c, 0xe7, 0xd3, 0x78, 0x8b, 0x96, 0x40, 0x05, 0xe7, 0x96, 0xff, 0x80, //0x8420,
|
||||
0x08, 0xc3, 0x79, 0x8b, 0xe7, 0x78, 0x8c, 0x96, 0xff, 0x78, 0x8f, 0xa6, 0x07, 0xe5, 0x1f, 0x64, //0x8430,
|
||||
0x02, 0x70, 0x69, 0x90, 0x0e, 0x91, 0x93, 0xff, 0x18, 0xe6, 0xc3, 0x9f, 0x50, 0x72, 0x12, 0x0c, //0x8440,
|
||||
0x4a, 0x12, 0x0c, 0x2f, 0x90, 0x0e, 0x8e, 0x12, 0x0c, 0x38, 0x78, 0x80, 0x12, 0x0c, 0x6b, 0x7b, //0x8450,
|
||||
0x04, 0x12, 0x0c, 0x1d, 0xc3, 0x12, 0x06, 0x45, 0x50, 0x56, 0x90, 0x0e, 0x92, 0xe4, 0x93, 0xff, //0x8460,
|
||||
0x78, 0x8f, 0xe6, 0x9f, 0x40, 0x02, 0x80, 0x11, 0x90, 0x0e, 0x90, 0xe4, 0x93, 0xff, 0xd3, 0x78, //0x8470,
|
||||
0x89, 0xe6, 0x9f, 0x18, 0xe6, 0x94, 0x00, 0x40, 0x03, 0x75, 0x1f, 0x05, 0x12, 0x0c, 0x4a, 0x12, //0x8480,
|
||||
0x0c, 0x2f, 0x90, 0x0e, 0x8f, 0x12, 0x0c, 0x38, 0x78, 0x7e, 0x12, 0x0c, 0x6b, 0x7b, 0x40, 0x12, //0x8490,
|
||||
0x0c, 0x1d, 0xd3, 0x12, 0x06, 0x45, 0x40, 0x18, 0x75, 0x1f, 0x05, 0x22, 0xe5, 0x1f, 0xb4, 0x05, //0x84a0,
|
||||
0x0f, 0xd2, 0x01, 0xc2, 0x02, 0xe4, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x35, 0xd2, 0x33, 0xd2, 0x36, //0x84b0,
|
||||
0x22, 0xef, 0x8d, 0xf0, 0xa4, 0xa8, 0xf0, 0xcf, 0x8c, 0xf0, 0xa4, 0x28, 0xce, 0x8d, 0xf0, 0xa4, //0x84c0,
|
||||
0x2e, 0xfe, 0x22, 0xbc, 0x00, 0x0b, 0xbe, 0x00, 0x29, 0xef, 0x8d, 0xf0, 0x84, 0xff, 0xad, 0xf0, //0x84d0,
|
||||
0x22, 0xe4, 0xcc, 0xf8, 0x75, 0xf0, 0x08, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xec, 0x33, 0xfc, //0x84e0,
|
||||
0xee, 0x9d, 0xec, 0x98, 0x40, 0x05, 0xfc, 0xee, 0x9d, 0xfe, 0x0f, 0xd5, 0xf0, 0xe9, 0xe4, 0xce, //0x84f0,
|
||||
0xfd, 0x22, 0xed, 0xf8, 0xf5, 0xf0, 0xee, 0x84, 0x20, 0xd2, 0x1c, 0xfe, 0xad, 0xf0, 0x75, 0xf0, //0x8500,
|
||||
0x08, 0xef, 0x2f, 0xff, 0xed, 0x33, 0xfd, 0x40, 0x07, 0x98, 0x50, 0x06, 0xd5, 0xf0, 0xf2, 0x22, //0x8510,
|
||||
0xc3, 0x98, 0xfd, 0x0f, 0xd5, 0xf0, 0xea, 0x22, 0xe8, 0x8f, 0xf0, 0xa4, 0xcc, 0x8b, 0xf0, 0xa4, //0x8520,
|
||||
0x2c, 0xfc, 0xe9, 0x8e, 0xf0, 0xa4, 0x2c, 0xfc, 0x8a, 0xf0, 0xed, 0xa4, 0x2c, 0xfc, 0xea, 0x8e, //0x8530,
|
||||
0xf0, 0xa4, 0xcd, 0xa8, 0xf0, 0x8b, 0xf0, 0xa4, 0x2d, 0xcc, 0x38, 0x25, 0xf0, 0xfd, 0xe9, 0x8f, //0x8540,
|
||||
0xf0, 0xa4, 0x2c, 0xcd, 0x35, 0xf0, 0xfc, 0xeb, 0x8e, 0xf0, 0xa4, 0xfe, 0xa9, 0xf0, 0xeb, 0x8f, //0x8550,
|
||||
0xf0, 0xa4, 0xcf, 0xc5, 0xf0, 0x2e, 0xcd, 0x39, 0xfe, 0xe4, 0x3c, 0xfc, 0xea, 0xa4, 0x2d, 0xce, //0x8560,
|
||||
0x35, 0xf0, 0xfd, 0xe4, 0x3c, 0xfc, 0x22, 0x75, 0xf0, 0x08, 0x75, 0x82, 0x00, 0xef, 0x2f, 0xff, //0x8570,
|
||||
0xee, 0x33, 0xfe, 0xcd, 0x33, 0xcd, 0xcc, 0x33, 0xcc, 0xc5, 0x82, 0x33, 0xc5, 0x82, 0x9b, 0xed, //0x8580,
|
||||
0x9a, 0xec, 0x99, 0xe5, 0x82, 0x98, 0x40, 0x0c, 0xf5, 0x82, 0xee, 0x9b, 0xfe, 0xed, 0x9a, 0xfd, //0x8590,
|
||||
0xec, 0x99, 0xfc, 0x0f, 0xd5, 0xf0, 0xd6, 0xe4, 0xce, 0xfb, 0xe4, 0xcd, 0xfa, 0xe4, 0xcc, 0xf9, //0x85a0,
|
||||
0xa8, 0x82, 0x22, 0xb8, 0x00, 0xc1, 0xb9, 0x00, 0x59, 0xba, 0x00, 0x2d, 0xec, 0x8b, 0xf0, 0x84, //0x85b0,
|
||||
0xcf, 0xce, 0xcd, 0xfc, 0xe5, 0xf0, 0xcb, 0xf9, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, //0x85c0,
|
||||
0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xeb, 0x33, 0xfb, 0x10, 0xd7, 0x03, 0x99, 0x40, 0x04, 0xeb, //0x85d0,
|
||||
0x99, 0xfb, 0x0f, 0xd8, 0xe5, 0xe4, 0xf9, 0xfa, 0x22, 0x78, 0x18, 0xef, 0x2f, 0xff, 0xee, 0x33, //0x85e0,
|
||||
0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xc9, 0x33, 0xc9, 0x10, 0xd7, 0x05, 0x9b, 0xe9, 0x9a, //0x85f0,
|
||||
0x40, 0x07, 0xec, 0x9b, 0xfc, 0xe9, 0x9a, 0xf9, 0x0f, 0xd8, 0xe0, 0xe4, 0xc9, 0xfa, 0xe4, 0xcc, //0x8600,
|
||||
0xfb, 0x22, 0x75, 0xf0, 0x10, 0xef, 0x2f, 0xff, 0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xcc, 0x33, //0x8610,
|
||||
0xcc, 0xc8, 0x33, 0xc8, 0x10, 0xd7, 0x07, 0x9b, 0xec, 0x9a, 0xe8, 0x99, 0x40, 0x0a, 0xed, 0x9b, //0x8620,
|
||||
0xfd, 0xec, 0x9a, 0xfc, 0xe8, 0x99, 0xf8, 0x0f, 0xd5, 0xf0, 0xda, 0xe4, 0xcd, 0xfb, 0xe4, 0xcc, //0x8630,
|
||||
0xfa, 0xe4, 0xc8, 0xf9, 0x22, 0xeb, 0x9f, 0xf5, 0xf0, 0xea, 0x9e, 0x42, 0xf0, 0xe9, 0x9d, 0x42, //0x8640,
|
||||
0xf0, 0xe8, 0x9c, 0x45, 0xf0, 0x22, 0xe8, 0x60, 0x0f, 0xec, 0xc3, 0x13, 0xfc, 0xed, 0x13, 0xfd, //0x8650,
|
||||
0xee, 0x13, 0xfe, 0xef, 0x13, 0xff, 0xd8, 0xf1, 0x22, 0xe8, 0x60, 0x0f, 0xef, 0xc3, 0x33, 0xff, //0x8660,
|
||||
0xee, 0x33, 0xfe, 0xed, 0x33, 0xfd, 0xec, 0x33, 0xfc, 0xd8, 0xf1, 0x22, 0xe4, 0x93, 0xfc, 0x74, //0x8670,
|
||||
0x01, 0x93, 0xfd, 0x74, 0x02, 0x93, 0xfe, 0x74, 0x03, 0x93, 0xff, 0x22, 0xe6, 0xfb, 0x08, 0xe6, //0x8680,
|
||||
0xf9, 0x08, 0xe6, 0xfa, 0x08, 0xe6, 0xcb, 0xf8, 0x22, 0xec, 0xf6, 0x08, 0xed, 0xf6, 0x08, 0xee, //0x8690,
|
||||
0xf6, 0x08, 0xef, 0xf6, 0x22, 0xa4, 0x25, 0x82, 0xf5, 0x82, 0xe5, 0xf0, 0x35, 0x83, 0xf5, 0x83, //0x86a0,
|
||||
0x22, 0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, //0x86b0,
|
||||
0xa3, 0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, //0x86c0,
|
||||
0x60, 0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf, 0x90, 0x38, 0x04, 0x78, 0x52, 0x12, 0x0b, 0xfd, 0x90, //0x86d0,
|
||||
0x38, 0x00, 0xe0, 0xfe, 0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 0x12, 0x0b, 0x9e, 0x90, 0x38, 0x10, //0x86e0,
|
||||
0x12, 0x0b, 0x92, 0x90, 0x38, 0x06, 0x78, 0x54, 0x12, 0x0b, 0xfd, 0x90, 0x38, 0x02, 0xe0, 0xfe, //0x86f0,
|
||||
0xa3, 0xe0, 0xfd, 0xed, 0xff, 0xc3, 0x12, 0x0b, 0x9e, 0x90, 0x38, 0x12, 0x12, 0x0b, 0x92, 0xa3, //0x8700,
|
||||
0xe0, 0xb4, 0x31, 0x07, 0x78, 0x52, 0x79, 0x52, 0x12, 0x0c, 0x13, 0x90, 0x38, 0x14, 0xe0, 0xb4, //0x8710,
|
||||
0x71, 0x15, 0x78, 0x52, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, //0x8720,
|
||||
0xf9, 0x79, 0x53, 0xf7, 0xee, 0x19, 0xf7, 0x90, 0x38, 0x15, 0xe0, 0xb4, 0x31, 0x07, 0x78, 0x54, //0x8730,
|
||||
0x79, 0x54, 0x12, 0x0c, 0x13, 0x90, 0x38, 0x15, 0xe0, 0xb4, 0x71, 0x15, 0x78, 0x54, 0xe6, 0xfe, //0x8740,
|
||||
0x08, 0xe6, 0x78, 0x02, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x79, 0x55, 0xf7, 0xee, 0x19, //0x8750,
|
||||
0xf7, 0x79, 0x52, 0x12, 0x0b, 0xd9, 0x09, 0x12, 0x0b, 0xd9, 0xaf, 0x47, 0x12, 0x0b, 0xb2, 0xe5, //0x8760,
|
||||
0x44, 0xfb, 0x7a, 0x00, 0xfd, 0x7c, 0x00, 0x12, 0x04, 0xd3, 0x78, 0x5a, 0xa6, 0x06, 0x08, 0xa6, //0x8770,
|
||||
0x07, 0xaf, 0x45, 0x12, 0x0b, 0xb2, 0xad, 0x03, 0x7c, 0x00, 0x12, 0x04, 0xd3, 0x78, 0x56, 0xa6, //0x8780,
|
||||
0x06, 0x08, 0xa6, 0x07, 0xaf, 0x48, 0x78, 0x54, 0x12, 0x0b, 0xb4, 0xe5, 0x43, 0xfb, 0xfd, 0x7c, //0x8790,
|
||||
0x00, 0x12, 0x04, 0xd3, 0x78, 0x5c, 0xa6, 0x06, 0x08, 0xa6, 0x07, 0xaf, 0x46, 0x7e, 0x00, 0x78, //0x87a0,
|
||||
0x54, 0x12, 0x0b, 0xb6, 0xad, 0x03, 0x7c, 0x00, 0x12, 0x04, 0xd3, 0x78, 0x58, 0xa6, 0x06, 0x08, //0x87b0,
|
||||
0xa6, 0x07, 0xc3, 0x78, 0x5b, 0xe6, 0x94, 0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, 0x00, //0x87c0,
|
||||
0x08, 0x76, 0x08, 0xc3, 0x78, 0x5d, 0xe6, 0x94, 0x08, 0x18, 0xe6, 0x94, 0x00, 0x50, 0x05, 0x76, //0x87d0,
|
||||
0x00, 0x08, 0x76, 0x08, 0x78, 0x5a, 0x12, 0x0b, 0xc6, 0xff, 0xd3, 0x78, 0x57, 0xe6, 0x9f, 0x18, //0x87e0,
|
||||
0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x5a, 0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x57, 0x12, 0x0c, 0x08, //0x87f0,
|
||||
0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0x78, 0x5e, 0x12, 0x0b, 0xbe, 0xff, 0xd3, 0x78, 0x59, 0xe6, //0x8800,
|
||||
0x9f, 0x18, 0xe6, 0x9e, 0x40, 0x0e, 0x78, 0x5c, 0xe6, 0x13, 0xfe, 0x08, 0xe6, 0x78, 0x59, 0x12, //0x8810,
|
||||
0x0c, 0x08, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x00, 0xe4, 0xfc, 0xfd, 0x78, 0x62, 0x12, 0x06, 0x99, //0x8820,
|
||||
0x78, 0x5a, 0x12, 0x0b, 0xc6, 0x78, 0x57, 0x26, 0xff, 0xee, 0x18, 0x36, 0xfe, 0x78, 0x66, 0x12, //0x8830,
|
||||
0x0b, 0xbe, 0x78, 0x59, 0x26, 0xff, 0xee, 0x18, 0x36, 0xfe, 0xe4, 0xfc, 0xfd, 0x78, 0x6a, 0x12, //0x8840,
|
||||
0x06, 0x99, 0x12, 0x0b, 0xce, 0x78, 0x66, 0x12, 0x06, 0x8c, 0xd3, 0x12, 0x06, 0x45, 0x40, 0x08, //0x8850,
|
||||
0x12, 0x0b, 0xce, 0x78, 0x66, 0x12, 0x06, 0x99, 0x78, 0x54, 0x12, 0x0b, 0xd0, 0x78, 0x6a, 0x12, //0x8860,
|
||||
0x06, 0x8c, 0xd3, 0x12, 0x06, 0x45, 0x40, 0x0a, 0x78, 0x54, 0x12, 0x0b, 0xd0, 0x78, 0x6a, 0x12, //0x8870,
|
||||
0x06, 0x99, 0x78, 0x61, 0xe6, 0x90, 0x60, 0x01, 0xf0, 0x78, 0x65, 0xe6, 0xa3, 0xf0, 0x78, 0x69, //0x8880,
|
||||
0xe6, 0xa3, 0xf0, 0x78, 0x55, 0xe6, 0xa3, 0xf0, 0x7d, 0x01, 0x78, 0x61, 0x12, 0x0b, 0xe9, 0x24, //0x8890,
|
||||
0x01, 0x12, 0x0b, 0xa6, 0x78, 0x65, 0x12, 0x0b, 0xe9, 0x24, 0x02, 0x12, 0x0b, 0xa6, 0x78, 0x69, //0x88a0,
|
||||
0x12, 0x0b, 0xe9, 0x24, 0x03, 0x12, 0x0b, 0xa6, 0x78, 0x6d, 0x12, 0x0b, 0xe9, 0x24, 0x04, 0x12, //0x88b0,
|
||||
0x0b, 0xa6, 0x0d, 0xbd, 0x05, 0xd4, 0xc2, 0x0e, 0xc2, 0x06, 0x22, 0x85, 0x08, 0x41, 0x90, 0x30, //0x88c0,
|
||||
0x24, 0xe0, 0xf5, 0x3d, 0xa3, 0xe0, 0xf5, 0x3e, 0xa3, 0xe0, 0xf5, 0x3f, 0xa3, 0xe0, 0xf5, 0x40, //0x88d0,
|
||||
0xa3, 0xe0, 0xf5, 0x3c, 0xd2, 0x34, 0xe5, 0x41, 0x12, 0x06, 0xb1, 0x09, 0x31, 0x03, 0x09, 0x35, //0x88e0,
|
||||
0x04, 0x09, 0x3b, 0x05, 0x09, 0x3e, 0x06, 0x09, 0x41, 0x07, 0x09, 0x4a, 0x08, 0x09, 0x5b, 0x12, //0x88f0,
|
||||
0x09, 0x73, 0x18, 0x09, 0x89, 0x19, 0x09, 0x5e, 0x1a, 0x09, 0x6a, 0x1b, 0x09, 0xad, 0x80, 0x09, //0x8900,
|
||||
0xb2, 0x81, 0x0a, 0x1d, 0x8f, 0x0a, 0x09, 0x90, 0x0a, 0x1d, 0x91, 0x0a, 0x1d, 0x92, 0x0a, 0x1d, //0x8910,
|
||||
0x93, 0x0a, 0x1d, 0x94, 0x0a, 0x1d, 0x98, 0x0a, 0x17, 0x9f, 0x0a, 0x1a, 0xec, 0x00, 0x00, 0x0a, //0x8920,
|
||||
0x38, 0x12, 0x0f, 0x74, 0x22, 0x12, 0x0f, 0x74, 0xd2, 0x03, 0x22, 0xd2, 0x03, 0x22, 0xc2, 0x03, //0x8930,
|
||||
0x22, 0xa2, 0x37, 0xe4, 0x33, 0xf5, 0x3c, 0x02, 0x0a, 0x1d, 0xc2, 0x01, 0xc2, 0x02, 0xc2, 0x03, //0x8940,
|
||||
0x12, 0x0d, 0x0d, 0x75, 0x1e, 0x70, 0xd2, 0x35, 0x02, 0x0a, 0x1d, 0x02, 0x0a, 0x04, 0x85, 0x40, //0x8950,
|
||||
0x4a, 0x85, 0x3c, 0x4b, 0x12, 0x0a, 0xff, 0x02, 0x0a, 0x1d, 0x85, 0x4a, 0x40, 0x85, 0x4b, 0x3c, //0x8960,
|
||||
0x02, 0x0a, 0x1d, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x85, 0x40, 0x31, 0x85, 0x3f, 0x30, 0x85, 0x3e, //0x8970,
|
||||
0x2f, 0x85, 0x3d, 0x2e, 0x12, 0x0f, 0x46, 0x80, 0x1f, 0x75, 0x22, 0x00, 0x75, 0x23, 0x01, 0x74, //0x8980,
|
||||
0xff, 0xf5, 0x2d, 0xf5, 0x2c, 0xf5, 0x2b, 0xf5, 0x2a, 0x12, 0x0f, 0x46, 0x85, 0x2d, 0x40, 0x85, //0x8990,
|
||||
0x2c, 0x3f, 0x85, 0x2b, 0x3e, 0x85, 0x2a, 0x3d, 0xe4, 0xf5, 0x3c, 0x80, 0x70, 0x12, 0x0f, 0x16, //0x89a0,
|
||||
0x80, 0x6b, 0x85, 0x3d, 0x45, 0x85, 0x3e, 0x46, 0xe5, 0x47, 0xc3, 0x13, 0xff, 0xe5, 0x45, 0xc3, //0x89b0,
|
||||
0x9f, 0x50, 0x02, 0x8f, 0x45, 0xe5, 0x48, 0xc3, 0x13, 0xff, 0xe5, 0x46, 0xc3, 0x9f, 0x50, 0x02, //0x89c0,
|
||||
0x8f, 0x46, 0xe5, 0x47, 0xc3, 0x13, 0xff, 0xfd, 0xe5, 0x45, 0x2d, 0xfd, 0xe4, 0x33, 0xfc, 0xe5, //0x89d0,
|
||||
0x44, 0x12, 0x0f, 0x90, 0x40, 0x05, 0xe5, 0x44, 0x9f, 0xf5, 0x45, 0xe5, 0x48, 0xc3, 0x13, 0xff, //0x89e0,
|
||||
0xfd, 0xe5, 0x46, 0x2d, 0xfd, 0xe4, 0x33, 0xfc, 0xe5, 0x43, 0x12, 0x0f, 0x90, 0x40, 0x05, 0xe5, //0x89f0,
|
||||
0x43, 0x9f, 0xf5, 0x46, 0x12, 0x06, 0xd7, 0x80, 0x14, 0x85, 0x40, 0x48, 0x85, 0x3f, 0x47, 0x85, //0x8a00,
|
||||
0x3e, 0x46, 0x85, 0x3d, 0x45, 0x80, 0x06, 0x02, 0x06, 0xd7, 0x12, 0x0d, 0x7e, 0x90, 0x30, 0x24, //0x8a10,
|
||||
0xe5, 0x3d, 0xf0, 0xa3, 0xe5, 0x3e, 0xf0, 0xa3, 0xe5, 0x3f, 0xf0, 0xa3, 0xe5, 0x40, 0xf0, 0xa3, //0x8a20,
|
||||
0xe5, 0x3c, 0xf0, 0x90, 0x30, 0x23, 0xe4, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, //0x8a30,
|
||||
0xd0, 0x90, 0x3f, 0x0c, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x30, 0xe3, 0x74, 0x30, 0x36, 0x66, 0x90, //0x8a40,
|
||||
0x60, 0x19, 0xe0, 0xf5, 0x0a, 0xa3, 0xe0, 0xf5, 0x0b, 0x90, 0x60, 0x1d, 0xe0, 0xf5, 0x14, 0xa3, //0x8a50,
|
||||
0xe0, 0xf5, 0x15, 0x90, 0x60, 0x21, 0xe0, 0xf5, 0x0c, 0xa3, 0xe0, 0xf5, 0x0d, 0x90, 0x60, 0x29, //0x8a60,
|
||||
0xe0, 0xf5, 0x0e, 0xa3, 0xe0, 0xf5, 0x0f, 0x90, 0x60, 0x31, 0xe0, 0xf5, 0x10, 0xa3, 0xe0, 0xf5, //0x8a70,
|
||||
0x11, 0x90, 0x60, 0x39, 0xe0, 0xf5, 0x12, 0xa3, 0xe0, 0xf5, 0x13, 0x30, 0x01, 0x06, 0x30, 0x33, //0x8a80,
|
||||
0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x09, 0x30, 0x02, 0x06, 0x30, 0x33, 0x03, 0xd3, 0x80, 0x01, //0x8a90,
|
||||
0xc3, 0x92, 0x0a, 0x30, 0x33, 0x0c, 0x30, 0x03, 0x09, 0x20, 0x02, 0x06, 0x20, 0x01, 0x03, 0xd3, //0x8aa0,
|
||||
0x80, 0x01, 0xc3, 0x92, 0x0b, 0x90, 0x30, 0x01, 0xe0, 0x44, 0x40, 0xf0, 0xe0, 0x54, 0xbf, 0xf0, //0x8ab0,
|
||||
0xe5, 0x32, 0x30, 0xe1, 0x14, 0x30, 0x34, 0x11, 0x90, 0x30, 0x22, 0xe0, 0xf5, 0x08, 0xe4, 0xf0, //0x8ac0,
|
||||
0x30, 0x00, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x08, 0xe5, 0x32, 0x30, 0xe5, 0x12, 0x90, 0x56, //0x8ad0,
|
||||
0xa1, 0xe0, 0xf5, 0x09, 0x30, 0x31, 0x09, 0x30, 0x05, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0d, //0x8ae0,
|
||||
0x90, 0x3f, 0x0c, 0xe5, 0x32, 0xf0, 0xd0, 0xd0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, //0x8af0,
|
||||
0x0e, 0x7e, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xff, 0xc3, 0x90, 0x0e, 0x7c, 0x74, 0x01, 0x93, //0x8b00,
|
||||
0x9f, 0xff, 0xe4, 0x93, 0x9e, 0xfe, 0xe4, 0x8f, 0x3b, 0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0xab, //0x8b10,
|
||||
0x3b, 0xaa, 0x3a, 0xa9, 0x39, 0xa8, 0x38, 0xaf, 0x4b, 0xfc, 0xfd, 0xfe, 0x12, 0x05, 0x28, 0x12, //0x8b20,
|
||||
0x0d, 0xe1, 0xe4, 0x7b, 0xff, 0xfa, 0xf9, 0xf8, 0x12, 0x05, 0xb3, 0x12, 0x0d, 0xe1, 0x90, 0x0e, //0x8b30,
|
||||
0x69, 0xe4, 0x12, 0x0d, 0xf6, 0x12, 0x0d, 0xe1, 0xe4, 0x85, 0x4a, 0x37, 0xf5, 0x36, 0xf5, 0x35, //0x8b40,
|
||||
0xf5, 0x34, 0xaf, 0x37, 0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0xa3, 0x12, 0x0d, 0xf6, 0x8f, 0x37, //0x8b50,
|
||||
0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0xe5, 0x3b, 0x45, 0x37, 0xf5, 0x3b, 0xe5, 0x3a, 0x45, 0x36, //0x8b60,
|
||||
0xf5, 0x3a, 0xe5, 0x39, 0x45, 0x35, 0xf5, 0x39, 0xe5, 0x38, 0x45, 0x34, 0xf5, 0x38, 0xe4, 0xf5, //0x8b70,
|
||||
0x22, 0xf5, 0x23, 0x85, 0x3b, 0x31, 0x85, 0x3a, 0x30, 0x85, 0x39, 0x2f, 0x85, 0x38, 0x2e, 0x02, //0x8b80,
|
||||
0x0f, 0x46, 0xe0, 0xa3, 0xe0, 0x75, 0xf0, 0x02, 0xa4, 0xff, 0xae, 0xf0, 0xc3, 0x08, 0xe6, 0x9f, //0x8b90,
|
||||
0xf6, 0x18, 0xe6, 0x9e, 0xf6, 0x22, 0xff, 0xe5, 0xf0, 0x34, 0x60, 0x8f, 0x82, 0xf5, 0x83, 0xec, //0x8ba0,
|
||||
0xf0, 0x22, 0x78, 0x52, 0x7e, 0x00, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x02, 0x04, 0xc1, 0xe4, 0xfc, //0x8bb0,
|
||||
0xfd, 0x12, 0x06, 0x99, 0x78, 0x5c, 0xe6, 0xc3, 0x13, 0xfe, 0x08, 0xe6, 0x13, 0x22, 0x78, 0x52, //0x8bc0,
|
||||
0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xe4, 0xfc, 0xfd, 0x22, 0xe7, 0xc4, 0xf8, 0x54, 0xf0, 0xc8, 0x68, //0x8bd0,
|
||||
0xf7, 0x09, 0xe7, 0xc4, 0x54, 0x0f, 0x48, 0xf7, 0x22, 0xe6, 0xfc, 0xed, 0x75, 0xf0, 0x04, 0xa4, //0x8be0,
|
||||
0x22, 0x12, 0x06, 0x7c, 0x8f, 0x48, 0x8e, 0x47, 0x8d, 0x46, 0x8c, 0x45, 0x22, 0xe0, 0xfe, 0xa3, //0x8bf0,
|
||||
0xe0, 0xfd, 0xee, 0xf6, 0xed, 0x08, 0xf6, 0x22, 0x13, 0xff, 0xc3, 0xe6, 0x9f, 0xff, 0x18, 0xe6, //0x8c00,
|
||||
0x9e, 0xfe, 0x22, 0xe6, 0xc3, 0x13, 0xf7, 0x08, 0xe6, 0x13, 0x09, 0xf7, 0x22, 0xad, 0x39, 0xac, //0x8c10,
|
||||
0x38, 0xfa, 0xf9, 0xf8, 0x12, 0x05, 0x28, 0x8f, 0x3b, 0x8e, 0x3a, 0x8d, 0x39, 0x8c, 0x38, 0xab, //0x8c20,
|
||||
0x37, 0xaa, 0x36, 0xa9, 0x35, 0xa8, 0x34, 0x22, 0x93, 0xff, 0xe4, 0xfc, 0xfd, 0xfe, 0x12, 0x05, //0x8c30,
|
||||
0x28, 0x8f, 0x37, 0x8e, 0x36, 0x8d, 0x35, 0x8c, 0x34, 0x22, 0x78, 0x84, 0xe6, 0xfe, 0x08, 0xe6, //0x8c40,
|
||||
0xff, 0xe4, 0x8f, 0x37, 0x8e, 0x36, 0xf5, 0x35, 0xf5, 0x34, 0x22, 0x90, 0x0e, 0x8c, 0xe4, 0x93, //0x8c50,
|
||||
0x25, 0xe0, 0x24, 0x0a, 0xf8, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xe6, 0xfe, 0x08, 0xe6, 0xff, //0x8c60,
|
||||
0xe4, 0x8f, 0x3b, 0x8e, 0x3a, 0xf5, 0x39, 0xf5, 0x38, 0x22, 0x78, 0x4e, 0xe6, 0xfe, 0x08, 0xe6, //0x8c70,
|
||||
0xff, 0x22, 0xef, 0x25, 0xe0, 0x24, 0x4e, 0xf8, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x22, 0x78, 0x89, //0x8c80,
|
||||
0xef, 0x26, 0xf6, 0x18, 0xe4, 0x36, 0xf6, 0x22, 0x75, 0x89, 0x03, 0x75, 0xa8, 0x01, 0x75, 0xb8, //0x8c90,
|
||||
0x04, 0x75, 0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x15, 0x75, 0x37, 0x0d, 0x12, 0x0e, 0x9a, //0x8ca0,
|
||||
0x12, 0x00, 0x09, 0x12, 0x0f, 0x16, 0x12, 0x00, 0x06, 0xd2, 0x00, 0xd2, 0x34, 0xd2, 0xaf, 0x75, //0x8cb0,
|
||||
0x34, 0xff, 0x75, 0x35, 0x0e, 0x75, 0x36, 0x49, 0x75, 0x37, 0x03, 0x12, 0x0e, 0x9a, 0x30, 0x08, //0x8cc0,
|
||||
0x09, 0xc2, 0x34, 0x12, 0x08, 0xcb, 0xc2, 0x08, 0xd2, 0x34, 0x30, 0x0b, 0x09, 0xc2, 0x36, 0x12, //0x8cd0,
|
||||
0x02, 0x6c, 0xc2, 0x0b, 0xd2, 0x36, 0x30, 0x09, 0x09, 0xc2, 0x36, 0x12, 0x00, 0x0e, 0xc2, 0x09, //0x8ce0,
|
||||
0xd2, 0x36, 0x30, 0x0e, 0x03, 0x12, 0x06, 0xd7, 0x30, 0x35, 0xd3, 0x90, 0x30, 0x29, 0xe5, 0x1e, //0x8cf0,
|
||||
0xf0, 0xb4, 0x10, 0x05, 0x90, 0x30, 0x23, 0xe4, 0xf0, 0xc2, 0x35, 0x80, 0xc1, 0xe4, 0xf5, 0x4b, //0x8d00,
|
||||
0x90, 0x0e, 0x7a, 0x93, 0xff, 0xe4, 0x8f, 0x37, 0xf5, 0x36, 0xf5, 0x35, 0xf5, 0x34, 0xaf, 0x37, //0x8d10,
|
||||
0xae, 0x36, 0xad, 0x35, 0xac, 0x34, 0x90, 0x0e, 0x6a, 0x12, 0x0d, 0xf6, 0x8f, 0x37, 0x8e, 0x36, //0x8d20,
|
||||
0x8d, 0x35, 0x8c, 0x34, 0x90, 0x0e, 0x72, 0x12, 0x06, 0x7c, 0xef, 0x45, 0x37, 0xf5, 0x37, 0xee, //0x8d30,
|
||||
0x45, 0x36, 0xf5, 0x36, 0xed, 0x45, 0x35, 0xf5, 0x35, 0xec, 0x45, 0x34, 0xf5, 0x34, 0xe4, 0xf5, //0x8d40,
|
||||
0x22, 0xf5, 0x23, 0x85, 0x37, 0x31, 0x85, 0x36, 0x30, 0x85, 0x35, 0x2f, 0x85, 0x34, 0x2e, 0x12, //0x8d50,
|
||||
0x0f, 0x46, 0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 0x72, 0x12, 0x0d, 0xea, 0x12, 0x0f, 0x46, //0x8d60,
|
||||
0xe4, 0xf5, 0x22, 0xf5, 0x23, 0x90, 0x0e, 0x6e, 0x12, 0x0d, 0xea, 0x02, 0x0f, 0x46, 0xe5, 0x40, //0x8d70,
|
||||
0x24, 0xf2, 0xf5, 0x37, 0xe5, 0x3f, 0x34, 0x43, 0xf5, 0x36, 0xe5, 0x3e, 0x34, 0xa2, 0xf5, 0x35, //0x8d80,
|
||||
0xe5, 0x3d, 0x34, 0x28, 0xf5, 0x34, 0xe5, 0x37, 0xff, 0xe4, 0xfe, 0xfd, 0xfc, 0x78, 0x18, 0x12, //0x8d90,
|
||||
0x06, 0x69, 0x8f, 0x40, 0x8e, 0x3f, 0x8d, 0x3e, 0x8c, 0x3d, 0xe5, 0x37, 0x54, 0xa0, 0xff, 0xe5, //0x8da0,
|
||||
0x36, 0xfe, 0xe4, 0xfd, 0xfc, 0x78, 0x07, 0x12, 0x06, 0x56, 0x78, 0x10, 0x12, 0x0f, 0x9a, 0xe4, //0x8db0,
|
||||
0xff, 0xfe, 0xe5, 0x35, 0xfd, 0xe4, 0xfc, 0x78, 0x0e, 0x12, 0x06, 0x56, 0x12, 0x0f, 0x9d, 0xe4, //0x8dc0,
|
||||
0xff, 0xfe, 0xfd, 0xe5, 0x34, 0xfc, 0x78, 0x18, 0x12, 0x06, 0x56, 0x78, 0x08, 0x12, 0x0f, 0x9a, //0x8dd0,
|
||||
0x22, 0x8f, 0x3b, 0x8e, 0x3a, 0x8d, 0x39, 0x8c, 0x38, 0x22, 0x12, 0x06, 0x7c, 0x8f, 0x31, 0x8e, //0x8de0,
|
||||
0x30, 0x8d, 0x2f, 0x8c, 0x2e, 0x22, 0x93, 0xf9, 0xf8, 0x02, 0x06, 0x69, 0x00, 0x00, 0x00, 0x00, //0x8df0,
|
||||
0x12, 0x01, 0x17, 0x08, 0x31, 0x15, 0x53, 0x54, 0x44, 0x20, 0x20, 0x20, 0x20, 0x20, 0x13, 0x01, //0x8e00,
|
||||
0x10, 0x01, 0x56, 0x40, 0x1a, 0x30, 0x29, 0x7e, 0x00, 0x30, 0x04, 0x20, 0xdf, 0x30, 0x05, 0x40, //0x8e10,
|
||||
0xbf, 0x50, 0x03, 0x00, 0xfd, 0x50, 0x27, 0x01, 0xfe, 0x60, 0x00, 0x11, 0x00, 0x3f, 0x05, 0x30, //0x8e20,
|
||||
0x00, 0x3f, 0x06, 0x22, 0x00, 0x3f, 0x01, 0x2a, 0x00, 0x3f, 0x02, 0x00, 0x00, 0x36, 0x06, 0x07, //0x8e30,
|
||||
0x00, 0x3f, 0x0b, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x40, 0xbf, 0x30, 0x01, 0x00, //0x8e40,
|
||||
0xbf, 0x30, 0x29, 0x70, 0x00, 0x3a, 0x00, 0x00, 0xff, 0x3a, 0x00, 0x00, 0xff, 0x36, 0x03, 0x36, //0x8e50,
|
||||
0x02, 0x41, 0x44, 0x58, 0x20, 0x18, 0x10, 0x0a, 0x04, 0x04, 0x00, 0x03, 0xff, 0x64, 0x00, 0x00, //0x8e60,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x06, 0x00, 0x03, 0x51, 0x00, 0x7a, //0x8e70,
|
||||
0x50, 0x3c, 0x28, 0x1e, 0x10, 0x10, 0x50, 0x2d, 0x28, 0x16, 0x10, 0x10, 0x02, 0x00, 0x10, 0x0c, //0x8e80,
|
||||
0x10, 0x04, 0x0c, 0x6e, 0x06, 0x05, 0x00, 0xa5, 0x5a, 0x00, 0xae, 0x35, 0xaf, 0x36, 0xe4, 0xfd, //0x8e90,
|
||||
0xed, 0xc3, 0x95, 0x37, 0x50, 0x33, 0x12, 0x0f, 0xe2, 0xe4, 0x93, 0xf5, 0x38, 0x74, 0x01, 0x93, //0x8ea0,
|
||||
0xf5, 0x39, 0x45, 0x38, 0x60, 0x23, 0x85, 0x39, 0x82, 0x85, 0x38, 0x83, 0xe0, 0xfc, 0x12, 0x0f, //0x8eb0,
|
||||
0xe2, 0x74, 0x03, 0x93, 0x52, 0x04, 0x12, 0x0f, 0xe2, 0x74, 0x02, 0x93, 0x42, 0x04, 0x85, 0x39, //0x8ec0,
|
||||
0x82, 0x85, 0x38, 0x83, 0xec, 0xf0, 0x0d, 0x80, 0xc7, 0x22, 0x78, 0xbe, 0xe6, 0xd3, 0x08, 0xff, //0x8ed0,
|
||||
0xe6, 0x64, 0x80, 0xf8, 0xef, 0x64, 0x80, 0x98, 0x22, 0x93, 0xff, 0x7e, 0x00, 0xe6, 0xfc, 0x08, //0x8ee0,
|
||||
0xe6, 0xfd, 0x12, 0x04, 0xc1, 0x78, 0xc1, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0xd3, 0xef, 0x9d, 0xee, //0x8ef0,
|
||||
0x9c, 0x22, 0x78, 0xbd, 0xd3, 0xe6, 0x64, 0x80, 0x94, 0x80, 0x22, 0x25, 0xe0, 0x24, 0x0a, 0xf8, //0x8f00,
|
||||
0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x22, 0xe5, 0x3c, 0xd3, 0x94, 0x00, 0x40, 0x0b, 0x90, 0x0e, 0x88, //0x8f10,
|
||||
0x12, 0x0b, 0xf1, 0x90, 0x0e, 0x86, 0x80, 0x09, 0x90, 0x0e, 0x82, 0x12, 0x0b, 0xf1, 0x90, 0x0e, //0x8f20,
|
||||
0x80, 0xe4, 0x93, 0xf5, 0x44, 0xa3, 0xe4, 0x93, 0xf5, 0x43, 0xd2, 0x06, 0x30, 0x06, 0x03, 0xd3, //0x8f30,
|
||||
0x80, 0x01, 0xc3, 0x92, 0x0e, 0x22, 0xa2, 0xaf, 0x92, 0x32, 0xc2, 0xaf, 0xe5, 0x23, 0x45, 0x22, //0x8f40,
|
||||
0x90, 0x0e, 0x5d, 0x60, 0x0e, 0x12, 0x0f, 0xcb, 0xe0, 0xf5, 0x2c, 0x12, 0x0f, 0xc8, 0xe0, 0xf5, //0x8f50,
|
||||
0x2d, 0x80, 0x0c, 0x12, 0x0f, 0xcb, 0xe5, 0x30, 0xf0, 0x12, 0x0f, 0xc8, 0xe5, 0x31, 0xf0, 0xa2, //0x8f60,
|
||||
0x32, 0x92, 0xaf, 0x22, 0xd2, 0x01, 0xc2, 0x02, 0xe4, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x35, 0xd2, //0x8f70,
|
||||
0x33, 0xd2, 0x36, 0xd2, 0x01, 0xc2, 0x02, 0xf5, 0x1f, 0xf5, 0x1e, 0xd2, 0x35, 0xd2, 0x33, 0x22, //0x8f80,
|
||||
0xfb, 0xd3, 0xed, 0x9b, 0x74, 0x80, 0xf8, 0x6c, 0x98, 0x22, 0x12, 0x06, 0x69, 0xe5, 0x40, 0x2f, //0x8f90,
|
||||
0xf5, 0x40, 0xe5, 0x3f, 0x3e, 0xf5, 0x3f, 0xe5, 0x3e, 0x3d, 0xf5, 0x3e, 0xe5, 0x3d, 0x3c, 0xf5, //0x8fa0,
|
||||
0x3d, 0x22, 0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0x90, 0x3f, 0x0d, 0xe0, 0xf5, 0x33, 0xe5, 0x33, //0x8fb0,
|
||||
0xf0, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32, 0x90, 0x0e, 0x5f, 0xe4, 0x93, 0xfe, 0x74, 0x01, //0x8fc0,
|
||||
0x93, 0xf5, 0x82, 0x8e, 0x83, 0x22, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0xcd, 0x02, //0x8fd0,
|
||||
0x0c, 0x98, 0x8f, 0x82, 0x8e, 0x83, 0x75, 0xf0, 0x04, 0xed, 0x02, 0x06, 0xa5, //0x8fe0
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,698 @@
|
|||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"},
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _OV5640CFG_H
|
||||
#define _OV5640CFG_H
|
||||
|
||||
#include "ov5640.h"
|
||||
#if 1
|
||||
|
||||
const uint16_t ov5640_init_reg_tbl[][2]=
|
||||
{
|
||||
// 24MHz input clock, 24MHz PCLK
|
||||
{0x3008, 0x42}, // software power down, bit[6]
|
||||
{0x3103, 0x03}, // system clock from PLL, bit[1]
|
||||
{0x3017, 0xff}, // FREX, Vsync, HREF, PCLK, D[9:6] output enable
|
||||
{0x3018, 0xff}, // D[5:0], GPIO[1:0] output enable
|
||||
{0x3034, 0x1a}, // MIPI 10-bit
|
||||
{0x3035, 0x41},//0x41, // PLL
|
||||
{0x3036, 0x90}, // PLL
|
||||
{0x3037, 0x13},//0x13, // PLL root divider, bit[4], PLL pre-divider, bit[3:0]
|
||||
{0x3108, 0x01}, // PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2], SCLK root divider, bit[1:0]
|
||||
{0x3630, 0x36},
|
||||
{0x3631, 0x0e},
|
||||
{0x3632, 0xe2},
|
||||
{0x3633, 0x12},
|
||||
{0x3621, 0xe0},
|
||||
{0x3704, 0xa0},
|
||||
{0x3703, 0x5a},
|
||||
{0x3715, 0x78},
|
||||
{0x3717, 0x01},
|
||||
{0x370b, 0x60},
|
||||
{0x3705, 0x1a},
|
||||
{0x3905, 0x02},
|
||||
{0x3906, 0x10},
|
||||
{0x3901, 0x0a},
|
||||
{0x3731, 0x12},
|
||||
{0x3600, 0x08}, // VCM control
|
||||
{0x3601, 0x33}, // VCM control
|
||||
{0x302d, 0x60}, // system control
|
||||
{0x3620, 0x52},
|
||||
{0x371b, 0x20},
|
||||
{0x471c, 0x50},
|
||||
{0x3a13, 0x43}, // pre-gain = 1.047x
|
||||
{0x3a18, 0x00}, // gain ceiling
|
||||
{0x3a19, 0xf8}, // gain ceiling = 15.5x
|
||||
{0x3635, 0x13},
|
||||
{0x3636, 0x03},
|
||||
{0x3634, 0x40},
|
||||
{0x3622, 0x01},
|
||||
{0x3c01, 0x34}, // Band auto, bit[7]
|
||||
{0x3c04, 0x28}, // threshold low sum
|
||||
{0x3c05, 0x98}, // threshold high sum
|
||||
{0x3c06, 0x00}, // light meter 1 threshold[15:8]
|
||||
{0x3c07, 0x07}, // light meter 1 threshold[7:0]
|
||||
{0x3c08, 0x00}, // light meter 2 threshold[15:8]
|
||||
{0x3c09, 0x1c}, // light meter 2 threshold[7:0]
|
||||
{0x3c0a, 0x9c}, // sample number[15:8]
|
||||
{0x3c0b, 0x40}, // sample number[7:0]
|
||||
{0x3810, 0x00}, // Timing Hoffset[11:8]
|
||||
{0x3811, 0x10}, // Timing Hoffset[7:0]
|
||||
{0x3812, 0x00}, // Timing Voffset[10:8]
|
||||
{0x3708, 0x64},
|
||||
{0x4001, 0x02}, // BLC start from line 2
|
||||
{0x4005, 0x1a}, // BLC always update
|
||||
{0x3000, 0x00}, // enable blocks
|
||||
{0x3004, 0xff}, // enable clocks
|
||||
{0x300e, 0x58}, // MIPI power down, DVP enable
|
||||
{0x302e, 0x00},
|
||||
{0x4300, 0x61},
|
||||
{0X501F, 0x01},
|
||||
{0x3820, 0x40}, // flip
|
||||
{0x3821, 0x00}, // mirror
|
||||
{0x3814, 0x71}, // timing X inc
|
||||
{0x3815, 0x35}, // timing Y inc
|
||||
{0x3800, 0x00}, // HS
|
||||
{0x3801, 0x00}, // HS
|
||||
{0x3802, 0x00}, // VS
|
||||
{0x3803, 0x00}, // VS
|
||||
{0x3804, 0x0a}, // HW (HE)
|
||||
{0x3805, 0x3f}, // HW (HE)
|
||||
{0x3806, 0x07}, // VH (VE)
|
||||
{0x3807, 0x9f}, // VH (VE)
|
||||
{0x3808, (320 >> 8)}, // DVPHO
|
||||
{0x3809, (320 & 0xff)}, // DVPHO
|
||||
{0x380a, (240 >> 8)}, // DVPVO
|
||||
{0x380b, (240 & 0xff)}, // DVPVO
|
||||
{0x380c, 0x07}, // HTS
|
||||
{0x380d, 0x58}, // HTS
|
||||
{0x380e, 0x01}, // VTS
|
||||
{0x380f, 0xf0}, // VTS
|
||||
{0x3810, 0x00}, // HTS
|
||||
{0x3811, 0x08}, // HTS
|
||||
{0x3812, 0x00}, // VTS
|
||||
{0x3813, 0x02}, // VTS
|
||||
{0x3618, 0x00},
|
||||
{0x3612, 0x29},
|
||||
{0x3709, 0x52},
|
||||
{0x370c, 0x03},
|
||||
{0x3a02, 0x02}, // 60Hz max exposure
|
||||
{0x3a03, 0xe0}, // 60Hz max exposure
|
||||
{0x3a14, 0x02}, // 50Hz max exposure
|
||||
{0x3a15, 0xe0}, // 50Hz max exposure
|
||||
{0x4004, 0x02}, // BLC line number
|
||||
{0x3002, 0x1c}, // reset JFIFO, SFIFO, JPG
|
||||
{0x3006, 0xc3}, // disable clock of JPEG2x, JPEG
|
||||
{0x4713, 0x03}, // JPEG mode 3
|
||||
{0x4407, 0x04}, // Quantization scale
|
||||
{0x460b, 0x37},
|
||||
{0x460c, 0x20},
|
||||
{0x4837, 0x16}, // MIPI global timing
|
||||
{0x3824, 0x04}, // PCLK manual divider
|
||||
{0x5001, 0xA3}, // SDE on, scale on, UV average off, color matrix on, AWB on
|
||||
{0x3503, 0x00}, // AEC/AGC on
|
||||
{0x440e, 0x00},
|
||||
{0x5000, 0xa7}, // Lenc on, raw gamma on, BPC on, WPC on, CIP on
|
||||
{0x3a0f, 0x30}, // stable range in high
|
||||
{0x3a10, 0x28}, // stable range in low
|
||||
{0x3a1b, 0x30}, // stable range out high
|
||||
{0x3a1e, 0x26}, // stable range out low
|
||||
{0x3a11, 0x60}, // fast zone high
|
||||
{0x3a1f, 0x14}, // fast zone low
|
||||
{0x5800, 0x23},
|
||||
{0x5801, 0x14},
|
||||
{0x5802, 0x0f},
|
||||
{0x5803, 0x0f},
|
||||
{0x5804, 0x12},
|
||||
{0x5805, 0x26},
|
||||
{0x5806, 0x0c},
|
||||
{0x5807, 0x08},
|
||||
{0x5808, 0x05},
|
||||
{0x5809, 0x05},
|
||||
{0x580a, 0x08},
|
||||
{0x580b, 0x0d},
|
||||
{0x580c, 0x08},
|
||||
{0x580d, 0x03},
|
||||
{0x580e, 0x00},
|
||||
{0x580f, 0x00},
|
||||
{0x5810, 0x03},
|
||||
{0x5811, 0x09},
|
||||
{0x5812, 0x07},
|
||||
{0x5813, 0x03},
|
||||
{0x5814, 0x00},
|
||||
{0x5815, 0x01},
|
||||
{0x5816, 0x03},
|
||||
{0x5817, 0x08},
|
||||
{0x5818, 0x0d},
|
||||
{0x5819, 0x08},
|
||||
{0x581a, 0x05},
|
||||
{0x581b, 0x06},
|
||||
{0x581c, 0x08},
|
||||
{0x581d, 0x0e},
|
||||
{0x581e, 0x29},
|
||||
{0x581f, 0x17},
|
||||
{0x5820, 0x11},
|
||||
{0x5821, 0x11},
|
||||
{0x5822, 0x15},
|
||||
{0x5823, 0x28},
|
||||
{0x5824, 0x46},
|
||||
{0x5825, 0x26},
|
||||
{0x5826, 0x08},
|
||||
{0x5827, 0x26},
|
||||
{0x5828, 0x64},
|
||||
{0x5829, 0x26},
|
||||
{0x582a, 0x24},
|
||||
{0x582b, 0x22},
|
||||
{0x582c, 0x24},
|
||||
{0x582d, 0x24},
|
||||
{0x582e, 0x06},
|
||||
{0x582f, 0x22},
|
||||
{0x5830, 0x40},
|
||||
{0x5831, 0x42},
|
||||
{0x5832, 0x24},
|
||||
{0x5833, 0x26},
|
||||
{0x5834, 0x24},
|
||||
{0x5835, 0x22},
|
||||
{0x5836, 0x22},
|
||||
{0x5837, 0x26},
|
||||
{0x5838, 0x44},
|
||||
{0x5839, 0x24},
|
||||
{0x583a, 0x26},
|
||||
{0x583b, 0x28},
|
||||
{0x583c, 0x42},
|
||||
{0x583d, 0xce}, // lenc BR offset
|
||||
{0x5180, 0xff}, // AWB B block
|
||||
{0x5181, 0xf2}, // AWB control
|
||||
{0x5182, 0x00}, // [7:4] max local counter, [3:0] max fast counter
|
||||
{0x5183, 0x14}, // AWB advanced
|
||||
{0x5184, 0x25},
|
||||
{0x5185, 0x24},
|
||||
{0x5186, 0x09},
|
||||
{0x5187, 0x09},
|
||||
{0x5188, 0x09},
|
||||
{0x5189, 0x75},
|
||||
{0x518a, 0x54},
|
||||
{0x518b, 0xe0},
|
||||
{0x518c, 0xb2},
|
||||
{0x518d, 0x42},
|
||||
{0x518e, 0x3d},
|
||||
{0x518f, 0x56},
|
||||
{0x5190, 0x46},
|
||||
{0x5191, 0xf8}, // AWB top limit
|
||||
{0x5192, 0x04}, // AWB bottom limit
|
||||
{0x5193, 0x70}, // red limit
|
||||
{0x5194, 0xf0}, // green limit
|
||||
{0x5195, 0xf0}, // blue limit
|
||||
{0x5196, 0x03}, // AWB control
|
||||
{0x5197, 0x01}, // local limit
|
||||
{0x5198, 0x04},
|
||||
{0x5199, 0x12},
|
||||
{0x519a, 0x04},
|
||||
{0x519b, 0x00},
|
||||
{0x519c, 0x06},
|
||||
{0x519d, 0x82},
|
||||
{0x519e, 0x38}, // AWB control
|
||||
{0x5480, 0x01}, // Gamma bias plus on, bit[0]
|
||||
{0x5481, 0x08},
|
||||
{0x5482, 0x14},
|
||||
{0x5483, 0x28},
|
||||
{0x5484, 0x51},
|
||||
{0x5485, 0x65},
|
||||
{0x5486, 0x71},
|
||||
{0x5487, 0x7d},
|
||||
{0x5488, 0x87},
|
||||
{0x5489, 0x91},
|
||||
{0x548a, 0x9a},
|
||||
{0x548b, 0xaa},
|
||||
{0x548c, 0xb8},
|
||||
{0x548d, 0xcd},
|
||||
{0x548e, 0xdd},
|
||||
{0x548f, 0xea},
|
||||
{0x5490, 0x1d},
|
||||
{0x5381, 0x1e}, // CMX1 for Y
|
||||
{0x5382, 0x5b}, // CMX2 for Y
|
||||
{0x5383, 0x08}, // CMX3 for Y
|
||||
{0x5384, 0x0a}, // CMX4 for U
|
||||
{0x5385, 0x7e}, // CMX5 for U
|
||||
{0x5386, 0x88}, // CMX6 for U
|
||||
{0x5387, 0x7c}, // CMX7 for V
|
||||
{0x5388, 0x6c}, // CMX8 for V
|
||||
{0x5389, 0x10}, // CMX9 for V
|
||||
{0x538a, 0x01}, // sign[9]
|
||||
{0x538b, 0x98}, // sign[8:1]
|
||||
{0x5580, 0x06}, // saturation on, bit[1]
|
||||
{0x5583, 0x40},
|
||||
{0x5584, 0x10},
|
||||
{0x5589, 0x10},
|
||||
{0x558a, 0x00},
|
||||
{0x558b, 0xf8},
|
||||
{0x501d, 0x40}, // enable manual offset of contrast
|
||||
{0x5300, 0x08}, // CIP sharpen MT threshold 1
|
||||
{0x5301, 0x30}, // CIP sharpen MT threshold 2
|
||||
{0x5302, 0x10}, // CIP sharpen MT offset 1
|
||||
{0x5303, 0x00}, // CIP sharpen MT offset 2
|
||||
{0x5304, 0x08}, // CIP DNS threshold 1
|
||||
{0x5305, 0x30}, // CIP DNS threshold 2
|
||||
{0x5306, 0x08}, // CIP DNS offset 1
|
||||
{0x5307, 0x16}, // CIP DNS offset 2
|
||||
{0x5309, 0x08}, // CIP sharpen TH threshold 1
|
||||
{0x530a, 0x30}, // CIP sharpen TH threshold 2
|
||||
{0x530b, 0x04}, // CIP sharpen TH offset 1
|
||||
{0x530c, 0x06}, // CIP sharpen TH offset 2
|
||||
{0x5025, 0x00},
|
||||
{0x3008, 0x02}, // wake up from standby, bit[6]
|
||||
{0x4740, 0X21}, //VSYNC active HIGH
|
||||
};
|
||||
#else
|
||||
const uint16_t ov5640_init_reg_tbl[][2]=
|
||||
{
|
||||
//; for the setting , 24M Mlck input and 24M Plck output
|
||||
//;15fps YUV mode
|
||||
{0x3103 ,0x11},
|
||||
{0x3008 ,0x82},
|
||||
{0x3008 ,0x42},
|
||||
{0x3103 ,0x03},
|
||||
{0x3017 ,0xff},
|
||||
{0x3018 ,0xff},
|
||||
{0x3034 ,0x1a},
|
||||
{0x3035 ,0x11},
|
||||
{0x3036 ,0x46},
|
||||
{0x3037 ,0x13},
|
||||
{0x3108 ,0x01},
|
||||
{0x3630 ,0x36},
|
||||
{0x3631 ,0x0e},
|
||||
{0x3632 ,0xe2},
|
||||
{0x3633 ,0x12},
|
||||
{0x3621 ,0xe0},
|
||||
{0x3704 ,0xa0},
|
||||
{0x3703 ,0x5a},
|
||||
{0x3715 ,0x78},
|
||||
{0x3717 ,0x01},
|
||||
{0x370b ,0x60},
|
||||
{0x3705 ,0x1a},
|
||||
{0x3905 ,0x02},
|
||||
{0x3906 ,0x10},
|
||||
{0x3901 ,0x0a},
|
||||
{0x3731 ,0x12},
|
||||
{0x3600 ,0x08},
|
||||
{0x3601 ,0x33},
|
||||
{0x302d ,0x60},
|
||||
{0x3620 ,0x52},
|
||||
{0x371b ,0x20},
|
||||
{0x471c ,0x50},
|
||||
{0x3a13 ,0x43},
|
||||
{0x3a18 ,0x00},
|
||||
{0x3a19 ,0xf8},
|
||||
{0x3635 ,0x13},
|
||||
{0x3636 ,0x03},
|
||||
{0x3634 ,0x40},
|
||||
{0x3622 ,0x01},
|
||||
//Confidential For Actions Only
|
||||
{0x3c01 ,0x34},
|
||||
{0x3c04 ,0x28},
|
||||
{0x3c05 ,0x98},
|
||||
{0x3c06 ,0x00},
|
||||
{0x3c07 ,0x08},
|
||||
{0x3c08 ,0x00},
|
||||
{0x3c09 ,0x1c},
|
||||
{0x3c0a ,0x9c},
|
||||
{0x3c0b ,0x40},
|
||||
{0x3820 ,0x40},
|
||||
{0x3821 ,0x00},
|
||||
{0x3814 ,0x31},
|
||||
{0x3815 ,0x31},
|
||||
|
||||
// {0x3800 ,0x00},
|
||||
// {0x3801 ,0x00},
|
||||
// {0x3802 ,0x00},
|
||||
// {0x3803 ,0x04},
|
||||
// {0x3804 ,0x0a},
|
||||
// {0x3805 ,0x3f},
|
||||
// {0x3806 ,0x07},
|
||||
// {0x3807 ,0x9b},
|
||||
// {0x3808 ,0x02},
|
||||
// {0x3809 ,0x80},
|
||||
// {0x380a ,0x01},
|
||||
// {0x380b ,0xe0},
|
||||
// {0x380c ,0x07},
|
||||
// {0x380d ,0x68},
|
||||
// {0x380e ,0x03},
|
||||
// {0x380f ,0xd8},
|
||||
|
||||
{0x3800 ,0x0 },
|
||||
{0x3801 ,0x0 },
|
||||
{0x3802 ,0x0 },
|
||||
{0x3803 ,0x4 },
|
||||
{0x3804 ,0xa },
|
||||
{0x3805 ,0x3f},
|
||||
{0x3806 ,0x7 },
|
||||
{0x3807 ,0x9b},
|
||||
{0x3808 ,0x1 },
|
||||
{0x3809 ,0x40},
|
||||
{0x380a ,0x0 },
|
||||
{0x380b ,0xf0},
|
||||
{0x380c ,0x7 },
|
||||
{0x380d ,0x68},
|
||||
{0x380e ,0x3 },
|
||||
{0x380f ,0xd8},
|
||||
|
||||
|
||||
{0x3810 ,0x00},
|
||||
{0x3811 ,0x10},
|
||||
{0x3812 ,0x00},
|
||||
{0x3813 ,0x06},
|
||||
{0x3618 ,0x00},
|
||||
{0x3612 ,0x29},
|
||||
{0x3708 ,0x64},
|
||||
{0x3709 ,0x52},
|
||||
{0x370c ,0x03},
|
||||
{0x3a02 ,0x03},
|
||||
{0x3a03 ,0xd8},
|
||||
{0x3a08 ,0x01},
|
||||
{0x3a09 ,0x27},
|
||||
{0x3a0a ,0x00},
|
||||
{0x3a0b ,0xf6},
|
||||
{0x3a0e ,0x03},
|
||||
{0x3a0d ,0x04},
|
||||
{0x3a14 ,0x03},
|
||||
{0x3a15 ,0xd8},
|
||||
//Confidential For Actions Only
|
||||
{0x4001 ,0x02},
|
||||
{0x4004 ,0x02},
|
||||
{0x3000 ,0x00},
|
||||
{0x3002 ,0x1c},
|
||||
{0x3004 ,0xff},
|
||||
{0x3006 ,0xc3},
|
||||
{0x300e ,0x58},
|
||||
{0x302e ,0x00},
|
||||
// {0x4300 ,0x30},
|
||||
// {0x501f ,0x00},
|
||||
{0x4300 ,0x61},
|
||||
{0x501f ,0x01},
|
||||
|
||||
{0x4713 ,0x03},
|
||||
{0x4407 ,0x04},
|
||||
{0x440e ,0x00},
|
||||
{0x460b ,0x35},
|
||||
{0x460c ,0x22},
|
||||
{0x3824 ,0x02},
|
||||
{0x5000 ,0xa7},
|
||||
{0x5001 ,0xa3},
|
||||
{0x5180 ,0xff},
|
||||
{0x5181 ,0xf2},
|
||||
{0x5182 ,0x00},
|
||||
{0x5183 ,0x14},
|
||||
{0x5184 ,0x25},
|
||||
{0x5185 ,0x24},
|
||||
{0x5186 ,0x09},
|
||||
{0x5187 ,0x09},
|
||||
{0x5188 ,0x09},
|
||||
{0x5189 ,0x75},
|
||||
{0x518a ,0x54},
|
||||
{0x518b ,0xe0},
|
||||
{0x518c ,0xb2},
|
||||
{0x518d ,0x42},
|
||||
{0x518e ,0x3d},
|
||||
{0x518f ,0x56},
|
||||
{0x5190 ,0x46},
|
||||
{0x5191 ,0xf8},
|
||||
{0x5192 ,0x04},
|
||||
{0x5193 ,0x70},
|
||||
{0x5194 ,0xf0},
|
||||
{0x5195 ,0xf0},
|
||||
{0x5196 ,0x03},
|
||||
{0x5197 ,0x01},
|
||||
{0x5198 ,0x04},
|
||||
{0x5199 ,0x12},
|
||||
{0x519a ,0x04},
|
||||
{0x519b ,0x00},
|
||||
{0x519c ,0x06},
|
||||
{0x519d ,0x82},
|
||||
//Confidential For Actions Only
|
||||
{0x519e ,0x38},
|
||||
{0x5381 ,0x1e},
|
||||
{0x5382 ,0x5b},
|
||||
{0x5383 ,0x08},
|
||||
{0x5384 ,0x0a},
|
||||
{0x5385 ,0x7e},
|
||||
{0x5386 ,0x88},
|
||||
{0x5387 ,0x7c},
|
||||
{0x5388 ,0x6c},
|
||||
{0x5389 ,0x10},
|
||||
{0x538a ,0x01},
|
||||
{0x538b ,0x98},
|
||||
{0x5300 ,0x08},
|
||||
{0x5301 ,0x30},
|
||||
{0x5302 ,0x10},
|
||||
{0x5303 ,0x00},
|
||||
{0x5304 ,0x08},
|
||||
{0x5305 ,0x30},
|
||||
{0x5306 ,0x08},
|
||||
{0x5307 ,0x16},
|
||||
{0x5309 ,0x08},
|
||||
{0x530a ,0x30},
|
||||
{0x530b ,0x04},
|
||||
{0x530c ,0x06},
|
||||
{0x5480 ,0x01},
|
||||
{0x5481 ,0x08},
|
||||
{0x5482 ,0x14},
|
||||
{0x5483 ,0x28},
|
||||
{0x5484 ,0x51},
|
||||
{0x5485 ,0x65},
|
||||
{0x5486 ,0x71},
|
||||
{0x5487 ,0x7d},
|
||||
{0x5488 ,0x87},
|
||||
{0x5489 ,0x91},
|
||||
{0x548a ,0x9a},
|
||||
{0x548b ,0xaa},
|
||||
{0x548c ,0xb8},
|
||||
{0x548d ,0xcd},
|
||||
{0x548e ,0xdd},
|
||||
{0x548f ,0xea},
|
||||
{0x5490 ,0x1d},
|
||||
{0x5580 ,0x02},
|
||||
{0x5583 ,0x40},
|
||||
{0x5584 ,0x10},
|
||||
{0x5589 ,0x10},
|
||||
{0x558a ,0x00},
|
||||
{0x558b ,0xf8},
|
||||
{0x5800 ,0x23},
|
||||
//Confidential For Actions Only
|
||||
{0x5801 ,0x14},
|
||||
{0x5802 ,0x0f},
|
||||
{0x5803 ,0x0f},
|
||||
{0x5804 ,0x12},
|
||||
{0x5805 ,0x26},
|
||||
{0x5806 ,0x0c},
|
||||
{0x5807 ,0x08},
|
||||
{0x5808 ,0x05},
|
||||
{0x5809 ,0x05},
|
||||
{0x580a ,0x08},
|
||||
{0x580b ,0x0d},
|
||||
{0x580c ,0x08},
|
||||
{0x580d ,0x03},
|
||||
{0x580e ,0x00},
|
||||
{0x580f ,0x00},
|
||||
{0x5810 ,0x03},
|
||||
{0x5811 ,0x09},
|
||||
{0x5812 ,0x07},
|
||||
{0x5813 ,0x03},
|
||||
{0x5814 ,0x00},
|
||||
{0x5815 ,0x01},
|
||||
{0x5816 ,0x03},
|
||||
{0x5817 ,0x08},
|
||||
{0x5818 ,0x0d},
|
||||
{0x5819 ,0x08},
|
||||
{0x581a ,0x05},
|
||||
{0x581b ,0x06},
|
||||
{0x581c ,0x08},
|
||||
{0x581d ,0x0e},
|
||||
{0x581e ,0x29},
|
||||
{0x581f ,0x17},
|
||||
{0x5820 ,0x11},
|
||||
{0x5821 ,0x11},
|
||||
{0x5822 ,0x15},
|
||||
{0x5823 ,0x28},
|
||||
{0x5824 ,0x46},
|
||||
{0x5825 ,0x26},
|
||||
{0x5826 ,0x08},
|
||||
{0x5827 ,0x26},
|
||||
{0x5828 ,0x64},
|
||||
{0x5829 ,0x26},
|
||||
{0x582a ,0x24},
|
||||
{0x582b ,0x22},
|
||||
{0x582c ,0x24},
|
||||
{0x582d ,0x24},
|
||||
{0x582e ,0x06},
|
||||
{0x582f ,0x22},
|
||||
{0x5830 ,0x40},
|
||||
//Confidential For Actions Only
|
||||
{0x5831 ,0x42},
|
||||
{0x5832 ,0x24},
|
||||
{0x5833 ,0x26},
|
||||
{0x5834 ,0x24},
|
||||
{0x5835 ,0x22},
|
||||
{0x5836 ,0x22},
|
||||
{0x5837 ,0x26},
|
||||
{0x5838 ,0x44},
|
||||
{0x5839 ,0x24},
|
||||
{0x583a ,0x26},
|
||||
{0x583b ,0x28},
|
||||
{0x583c ,0x42},
|
||||
{0x583d ,0xce},
|
||||
{0x5025 ,0x00},
|
||||
{0x3a0f ,0x30},
|
||||
{0x3a10 ,0x28},
|
||||
{0x3a1b ,0x30},
|
||||
{0x3a1e ,0x26},
|
||||
{0x3a11 ,0x60},
|
||||
{0x3a1f ,0x14},
|
||||
{0x3008 ,0x02},
|
||||
{0x3035 ,0x21},
|
||||
//Band,0x50Hz
|
||||
{0x3c01,0xb4},
|
||||
{0x3c00,0x04},
|
||||
//gain ceiling
|
||||
{0x3a19,0x7c},
|
||||
//OV5640 LENC setting
|
||||
{0x5800 ,0x2c},
|
||||
{0x5801 ,0x17},
|
||||
{0x5802 ,0x11},
|
||||
{0x5803 ,0x11},
|
||||
{0x5804 ,0x15},
|
||||
{0x5805 ,0x29},
|
||||
{0x5806 ,0x08},
|
||||
{0x5807 ,0x06},
|
||||
{0x5808 ,0x04},
|
||||
{0x5809 ,0x04},
|
||||
{0x580a ,0x05},
|
||||
{0x580b ,0x07},
|
||||
{0x580c ,0x06},
|
||||
{0x580d ,0x03},
|
||||
{0x580e ,0x01},
|
||||
{0x580f ,0x01},
|
||||
{0x5810 ,0x03},
|
||||
{0x5811 ,0x06},
|
||||
//Confidential For Actions Only
|
||||
{0x5812 ,0x06},
|
||||
{0x5813 ,0x02},
|
||||
{0x5814 ,0x01},
|
||||
{0x5815 ,0x01},
|
||||
{0x5816 ,0x04},
|
||||
{0x5817 ,0x07},
|
||||
{0x5818 ,0x06},
|
||||
{0x5819 ,0x07},
|
||||
{0x581a ,0x06},
|
||||
{0x581b ,0x06},
|
||||
{0x581c ,0x06},
|
||||
{0x581d ,0x0e},
|
||||
{0x581e ,0x31},
|
||||
{0x581f ,0x12},
|
||||
{0x5820 ,0x11},
|
||||
{0x5821 ,0x11},
|
||||
{0x5822 ,0x11},
|
||||
{0x5823 ,0x2f},
|
||||
{0x5824 ,0x12},
|
||||
{0x5825 ,0x25},
|
||||
{0x5826 ,0x39},
|
||||
{0x5827 ,0x29},
|
||||
{0x5828 ,0x27},
|
||||
{0x5829 ,0x39},
|
||||
{0x582a ,0x26},
|
||||
{0x582b ,0x33},
|
||||
{0x582c ,0x24},
|
||||
{0x582d ,0x39},
|
||||
{0x582e ,0x28},
|
||||
{0x582f ,0x21},
|
||||
{0x5830 ,0x40},
|
||||
{0x5831 ,0x21},
|
||||
{0x5832 ,0x17},
|
||||
{0x5833 ,0x17},
|
||||
{0x5834 ,0x15},
|
||||
{0x5835 ,0x11},
|
||||
{0x5836 ,0x24},
|
||||
{0x5837 ,0x27},
|
||||
{0x5838 ,0x26},
|
||||
{0x5839 ,0x26},
|
||||
{0x583a ,0x26},
|
||||
{0x583b ,0x28},
|
||||
{0x583c ,0x14},
|
||||
{0x583d ,0xee},
|
||||
{0x4005 ,0x1a},
|
||||
//color
|
||||
{0x5381,0x26},
|
||||
{0x5382,0x50},
|
||||
//Confidential For Actions Only
|
||||
{0x5383,0x0c},
|
||||
{0x5384,0x09},
|
||||
{0x5385,0x74},
|
||||
{0x5386,0x7d},
|
||||
{0x5387,0x7e},
|
||||
{0x5388,0x75},
|
||||
{0x5389,0x09},
|
||||
{0x538b,0x98},
|
||||
{0x538a,0x01},
|
||||
//UVAdjust Auto Mode
|
||||
{0x5580,0x02},
|
||||
{0x5588,0x01},
|
||||
{0x5583,0x40},
|
||||
{0x5584,0x10},
|
||||
{0x5589,0x0f},
|
||||
{0x558a,0x00},
|
||||
{0x558b,0x3f},
|
||||
//De-Noise,0xAuto
|
||||
{0x5308,0x25},
|
||||
{0x5304,0x08},
|
||||
{0x5305,0x30},
|
||||
{0x5306,0x10},
|
||||
{0x5307,0x20},
|
||||
//awb
|
||||
{0x5180,0xff},
|
||||
{0x5181,0xf2},
|
||||
{0x5182,0x11},
|
||||
{0x5183,0x14},
|
||||
{0x5184,0x25},
|
||||
{0x5185,0x24},
|
||||
{0x5186,0x10},
|
||||
{0x5187,0x12},
|
||||
{0x5188,0x10},
|
||||
{0x5189,0x80},
|
||||
{0x518a,0x54},
|
||||
{0x518b,0xb8},
|
||||
{0x518c,0xb2},
|
||||
{0x518d,0x42},
|
||||
{0x518e,0x3a},
|
||||
{0x518f,0x56},
|
||||
{0x5190,0x46},
|
||||
{0x5191,0xf0},
|
||||
{0x5192,0xf},
|
||||
{0x5193,0x70},
|
||||
//Confidential For Actions Only
|
||||
{0x5194,0xf0},
|
||||
{0x5195,0xf0},
|
||||
{0x5196,0x3},
|
||||
{0x5197,0x1},
|
||||
{0x5198,0x6},
|
||||
{0x5199,0x62},
|
||||
{0x519a,0x4},
|
||||
{0x519b,0x0},
|
||||
{0x519c,0x4},
|
||||
{0x519d,0xe7},
|
||||
{0x519e,0x38},
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Face Detection
|
||||
=====
|
||||
The kmodel is generated by nncase.
|
||||
If LOAD_KMODEL_FROM_FLASH == 1, load kmode from flash
|
||||
|
||||
SDK v0.5.4 or later.
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef _BOARD_CONFIG_
|
||||
#define _BOARD_CONFIG_
|
||||
|
||||
#define OV5640 1
|
||||
#define OV2640 0
|
||||
|
||||
#define BOARD_KD233 1
|
||||
#define BOARD_LICHEEDAN 0
|
||||
|
||||
#if OV5640 + OV2640 != 1
|
||||
#error ov sensor only choose one
|
||||
#endif
|
||||
|
||||
#if BOARD_KD233 + BOARD_LICHEEDAN != 1
|
||||
#error board only choose one
|
||||
#endif
|
||||
|
||||
#endif
|
Binary file not shown.
|
@ -0,0 +1,352 @@
|
|||
#ifndef _FONT_H_
|
||||
#define _FONT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint8_t const ascii0816[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD,
|
||||
0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF,
|
||||
0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE,
|
||||
0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
|
||||
0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
|
||||
0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD,
|
||||
0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E,
|
||||
0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30,
|
||||
0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63,
|
||||
0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8,
|
||||
0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E,
|
||||
0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB,
|
||||
0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6,
|
||||
0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
|
||||
0x7E, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0,
|
||||
0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C,
|
||||
0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
|
||||
0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x06, 0x86, 0xC6, 0x7C,
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18,
|
||||
0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C,
|
||||
0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xD6, 0xD6, 0xC6, 0xC6, 0x6C, 0x38,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
|
||||
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE,
|
||||
0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
|
||||
0xC0, 0xC0, 0xFC, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18,
|
||||
0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
|
||||
0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
|
||||
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00,
|
||||
0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
|
||||
0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE,
|
||||
0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
|
||||
0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
|
||||
0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
|
||||
0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xE6, 0x66, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60,
|
||||
0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE,
|
||||
0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66,
|
||||
0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C,
|
||||
0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C,
|
||||
0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
|
||||
0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0xEE, 0x6C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38,
|
||||
0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
|
||||
0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
|
||||
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60,
|
||||
0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60,
|
||||
0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06,
|
||||
0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60,
|
||||
0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6,
|
||||
0xD6, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0x60, 0x60, 0xF0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60,
|
||||
0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
|
||||
0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xC6, 0xC6, 0xD6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
|
||||
0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6,
|
||||
0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
|
||||
0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
|
||||
0x00, 0x00, 0xCC, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE,
|
||||
0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C,
|
||||
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xCC, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38,
|
||||
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06,
|
||||
0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE,
|
||||
0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
|
||||
0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66,
|
||||
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6,
|
||||
0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00,
|
||||
0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36,
|
||||
0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C,
|
||||
0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0x00, 0x7C, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
|
||||
0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00,
|
||||
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00,
|
||||
0x00, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
|
||||
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C,
|
||||
0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
|
||||
0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC,
|
||||
0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30,
|
||||
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC,
|
||||
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC,
|
||||
0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
|
||||
0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
|
||||
0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
|
||||
0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xDC, 0x86, 0x0C,
|
||||
0x18, 0x3E, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
|
||||
0x66, 0xCE, 0x9E, 0x3E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
|
||||
0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6C, 0xD8, 0x6C, 0x36, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x6C, 0x36,
|
||||
0x6C, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
|
||||
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
|
||||
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
|
||||
0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
|
||||
0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
|
||||
0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0xD8, 0xCC, 0xC6, 0xC6, 0xC6, 0xCC,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0,
|
||||
0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8,
|
||||
0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66,
|
||||
0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
|
||||
0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66,
|
||||
0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xDB, 0xDB, 0xF3, 0x7E, 0x60, 0xC0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60,
|
||||
0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C,
|
||||
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
|
||||
0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
|
||||
0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00,
|
||||
0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
|
||||
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C,
|
||||
0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xD8, 0x30, 0x60, 0xC8, 0xF8, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
#endif
|
||||
|
63
lib/nncase/include/runtime/cpu/interpreter.h → src/face_detect/image_process.c
Normal file → Executable file
63
lib/nncase/include/runtime/cpu/interpreter.h → src/face_detect/image_process.c
Normal file → Executable file
|
@ -1,31 +1,32 @@
|
|||
/* Copyright 2019 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <runtime/interpreter.h>
|
||||
|
||||
namespace nncase
|
||||
{
|
||||
namespace runtime
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
class interpreter : public runtime::interpreter_base
|
||||
{
|
||||
public:
|
||||
using interpreter_base::interpreter_base;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Copyright 2018 Canaan Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "image_process.h"
|
||||
#include "iomem.h"
|
||||
|
||||
int image_init(image_t *image)
|
||||
{
|
||||
image->addr = iomem_malloc(image->width * image->height * image->pixel);
|
||||
if (image->addr == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void image_deinit(image_t *image)
|
||||
{
|
||||
iomem_free(image->addr);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue