diff --git a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/ARM/startup_LPC43xx_M0.s b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/ARM/startup_LPC43xx_M0.s index c5a5dbefd96a0649be81c39eca0cfb1148cd7d87..efda7f9c2b3f328a7fcd5b11a0201ec4e36f02cb 100644 --- a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/ARM/startup_LPC43xx_M0.s +++ b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/ARM/startup_LPC43xx_M0.s @@ -96,10 +96,10 @@ __Vectors DCD __initial_sp ; 0 Top of Stack DCD ADC1_IRQHandler ; 37 ADC1 DCD SSP0_OR_SSP1_IRQHandler ; 38 SSP0 or SSP1 DCD EVENTROUTER_IRQHandler ; 39 Event router - DCD USART0_IRQHandler ; 40 USART0 + DCD UART0_IRQHandler ; 40 USART0 DCD UART1_IRQHandler ; 41 UART1/Modem - DCD USART2_OR_C_CAN1_IRQHandler ; 42 USART2 or C CAN1 - DCD USART3_IRQHandler ; 43 USART3 + DCD UART2_OR_C_CAN1_IRQHandler ; 42 USART2 or C CAN1 + DCD UART3_IRQHandler ; 43 USART3 DCD I2S0_OR_I2S1_OR_QEI_IRQHandler ; 44 I2S0 or I2S1 or QEI DCD C_CAN0_IRQHandler ; 45 C CAN0 DCD 0 ; 46 Reserved @@ -175,10 +175,10 @@ Default_Handler PROC EXPORT ADC1_IRQHandler [WEAK] EXPORT SSP0_OR_SSP1_IRQHandler [WEAK] EXPORT EVENTROUTER_IRQHandler [WEAK] - EXPORT USART0_IRQHandler [WEAK] + EXPORT UART0_IRQHandler [WEAK] EXPORT UART1_IRQHandler [WEAK] - EXPORT USART2_OR_C_CAN1_IRQHandler [WEAK] - EXPORT USART3_IRQHandler [WEAK] + EXPORT UART2_OR_C_CAN1_IRQHandler [WEAK] + EXPORT UART3_IRQHandler [WEAK] EXPORT I2S0_OR_I2S1_OR_QEI_IRQHandler [WEAK] EXPORT C_CAN0_IRQHandler [WEAK] @@ -206,10 +206,10 @@ SPI_OR_DAC_IRQHandler ADC1_IRQHandler SSP0_OR_SSP1_IRQHandler EVENTROUTER_IRQHandler -USART0_IRQHandler +UART0_IRQHandler UART1_IRQHandler -USART2_OR_C_CAN1_IRQHandler -USART3_IRQHandler +UART2_OR_C_CAN1_IRQHandler +UART3_IRQHandler I2S0_OR_I2S1_OR_QEI_IRQHandler C_CAN0_IRQHandler diff --git a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx.s b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx.s index 879e33872dd0011119d73690c094ab44b709b332..9d8b409c2c304bef72e858a800050a06c852a20f 100644 --- a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx.s +++ b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx.s @@ -109,30 +109,56 @@ __interrupt_vector: .type Reset_Handler, %function Reset_Handler: .fnstart -.ifdef RAM_MODE -/* Clear .bss section (Zero init) */ - mov R0, #0 - ldr R1, =__bss_start__ - ldr R2, =__bss_end__ - cmp R1,R2 - beq BSSIsEmpty -LoopZI: - cmp R1, R2 - bhs BSSIsEmpty - str R0, [R1] - add R1, #4 - blo LoopZI -BSSIsEmpty: - ldr R0, =SystemInit - blx R0 - ldr R0,=main - bx R0 -.else +/* Single section scheme. + * + * The ranges of copy from/to are specified by following symbols + * _sidata: LMA of start of the section to copy from. Usually end of text + * _sdata: VMA of start of the section to copy to + * _edata: VMA of end of the section to copy to + * + * All addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + + subs r3, r2 + ble .L_loop1_done + +.L_loop1: + subs r3, #4 + ldr r0, [r1,r3] + str r0, [r2,r3] + bgt .L_loop1 + +.L_loop1_done: + +/* Single BSS section scheme. + * + * The BSS section is specified by following symbols + * __bss_start: start of the BSS section. + * __bss_end: end of the BSS section. + * + * Both addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =__bss_start + ldr r2, =__bss_end + + movs r0, 0 + + subs r2, r1 + ble .L_loop3_done + +.L_loop3: + subs r2, #4 + str r0, [r1, r2] + bgt .L_loop3 +.L_loop3_done: + ldr R0, =SystemInit blx R0 ldr R0,=main bx R0 -.endif .pool .cantunwind diff --git a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx_M0.s b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx_M0.s index 5a7b26405dd400b4cc0015c66e6b17b6d5cc84d9..39baf2409478cce007802bd382dc0d9d158b8993 100644 --- a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx_M0.s +++ b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/GCC/startup_LPC43xx_M0.s @@ -6,9 +6,9 @@ .syntax unified .cpu cortex-m0 - .fpu softvfp + .arch armv6-m .thumb - + .word _sidata .word _sdata .word _edata @@ -43,59 +43,38 @@ __interrupt_vector: .long SysTick_Handler /* SysTick Handler */ /* External Interrupts */ - .long DAC_IRQHandler /* 16 D/A Converter */ - .long M4CORE_IRQHandler /* 17 M0 Core */ - .long DMA_IRQHandler /* 18 General Purpose DMA */ - .long EZH_IRQHandler /* 19 EZH/EDM */ - .long FLASH_EEPROM_IRQHandler /* 20 Reserved for Typhoon */ - .long ETH_IRQHandler /* 21 Ethernet */ - .long SDIO_IRQHandler /* 22 SD/MMC */ - .long LCD_IRQHandler /* 23 LCD */ - .long USB0_IRQHandler /* 24 USB0 */ - .long USB1_IRQHandler /* 25 USB1 */ - .long SCT_IRQHandler /* 26 State Configurable Timer */ - .long RIT_IRQHandler /* 27 Repetitive Interrupt Timer*/ - .long TIMER0_IRQHandler /* 28 Timer0 */ - .long TIMER1_IRQHandler /* 29 Timer1 */ - .long TIMER2_IRQHandler /* 30 Timer2 */ - .long TIMER3_IRQHandler /* 31 Timer3 */ - .long MCPWM_IRQHandler /* 32 Motor Control PWM */ - .long ADC0_IRQHandler /* 33 A/D Converter 0 */ - .long I2C0_IRQHandler /* 34 I2C0 */ - .long I2C1_IRQHandler /* 35 I2C1 */ - .long SPI_IRQHandler /* 36 SPI */ - .long ADC1_IRQHandler /* 37 A/D Converter 1 */ - .long SSP0_IRQHandler /* 38 SSP0 */ - .long SSP1_IRQHandler /* 39 SSP1 */ - .long UART0_IRQHandler /* 40 UART0 */ - .long UART1_IRQHandler /* 41 UART1 */ - .long UART2_IRQHandler /* 42 UART2 */ - .long UART3_IRQHandler /* 43 UART3 */ - .long I2S0_IRQHandler /* 44 I2S0 */ - .long I2S1_IRQHandler /* 45 I2S1 */ - .long SPIFI_IRQHandler /* 46 SPI Flash Interface */ - .long SGPIO_IRQHandler /* 47 SGPIO */ - .long GPIO0_IRQHandler /* 48 GPIO0 */ - .long GPIO1_IRQHandler /* 49 GPIO1 */ - .long GPIO2_IRQHandler /* 50 GPIO2 */ - .long GPIO3_IRQHandler /* 51 GPIO3 */ - .long GPIO4_IRQHandler /* 52 GPIO4 */ - .long GPIO5_IRQHandler /* 53 GPIO5 */ - .long GPIO6_IRQHandler /* 54 GPIO6 */ - .long GPIO7_IRQHandler /* 55 GPIO7 */ - .long GINT0_IRQHandler /* 56 GINT0 */ - .long GINT1_IRQHandler /* 57 GINT1 */ - .long EVRT_IRQHandler /* 58 Event Router */ - .long CAN1_IRQHandler /* 59 C_CAN1 */ - .long 0 /* 60 Reserved */ - .long VADC_IRQHandler /* 61 VADC */ - .long ATIMER_IRQHandler /* 62 ATIMER */ - .long RTC_IRQHandler /* 63 RTC */ - .long 0 /* 64 Reserved */ - .long WDT_IRQHandler /* 65 WDT */ - .long M0s_IRQHandler /* 66 M0s */ - .long CAN0_IRQHandler /* 67 C_CAN0 */ - .long QEI_IRQHandler /* 68 QEI */ + .long RTC_IRQHandler /* 16 D/A Converter */ + .long M4CORE_IRQHandler /* 17 M0 Core */ + .long DMA_IRQHandler /* 18 General Purpose DMA */ + .long 0 /* 19 EZH/EDM */ + .long FLASHEEPROMAT_IRQHandler /* 20 Reserved for Typhoon */ + .long ETH_IRQHandler /* 21 Ethernet */ + .long SDIO_IRQHandler /* 22 SD/MMC */ + .long LCD_IRQHandler /* 23 LCD */ + .long USB0_IRQHandler /* 24 USB0 */ + .long USB1_IRQHandler /* 25 USB1 */ + .long SCT_IRQHandler /* 26 State Configurable Timer */ + .long RIT_OR_WWDT_IRQHandler /* 27 Repetitive Interrupt Timer*/ + .long TIMER0_IRQHandler /* 28 Timer0 */ + .long GINT1_IRQHandler /* 29 Timer1 */ + .long PIN_INT4_IRQHandler /* 30 Timer2 */ + .long TIMER3_IRQHandler /* 31 Timer3 */ + .long MCPWM_IRQHandler /* 32 Motor Control PWM */ + .long ADC0_IRQHandler /* 33 A/D Converter 0 */ + .long I2C0_OR_I2C1_IRQHandler /* 34 I2C0 */ + .long SGPIO_IRQHandler /* 35 I2C1 */ + .long SPI_OR_DAC_IRQHandler /* 36 SPI */ + .long ADC1_IRQHandler /* 37 A/D Converter 1 */ + .long SSP0_OR_SSP1_IRQHandler /* 38 SSP0 */ + .long EVENTROUTER_IRQHandler /* 39 SSP1 */ + .long UART0_IRQHandler /* 40 UART0 */ + .long UART1_IRQHandler /* 41 UART1 */ + .long UART2_OR_C_CAN1_IRQHandler /* 42 UART2 */ + .long UART3_IRQHandler /* 43 UART3 */ + .long I2S0_OR_I2S1_OR_QEI_IRQHandler /* 44 I2S0 */ + .long C_CAN0_IRQHandler /* 45 I2S1 */ + .long 0 /* 46 SPI Flash Interface */ + .long 0 /* 47 SGPIO */ .size __interrupt_vector, . - __interrupt_vector @@ -109,30 +88,56 @@ __interrupt_vector: .type Reset_Handler, %function Reset_Handler: .fnstart -.ifdef RAM_MODE -/* Clear .bss section (Zero init) */ - mov R0, #0 - ldr R1, =__bss_start__ - ldr R2, =__bss_end__ - cmp R1,R2 - beq BSSIsEmpty -LoopZI: - cmp R1, R2 - bhs BSSIsEmpty - str R0, [R1] - add R1, #4 - blo LoopZI -BSSIsEmpty: - ldr R0, =SystemInit - blx R0 - ldr R0,=main - bx R0 -.else +/* Single section scheme. + * + * The ranges of copy from/to are specified by following symbols + * _sidata: LMA of start of the section to copy from. Usually end of text + * _sdata: VMA of start of the section to copy to + * _edata: VMA of end of the section to copy to + * + * All addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =_sidata + ldr r2, =_sdata + ldr r3, =_edata + + subs r3, r2 + ble .L_loop1_done + +.L_loop1: + subs r3, #4 + ldr r0, [r1,r3] + str r0, [r2,r3] + bgt .L_loop1 + +.L_loop1_done: + +/* Single BSS section scheme. + * + * The BSS section is specified by following symbols + * __bss_start: start of the BSS section. + * __bss_end: end of the BSS section. + * + * Both addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =__bss_start + ldr r2, =__bss_end + + movs r0, 0 + + subs r2, r1 + ble .L_loop3_done + +.L_loop3: + subs r2, #4 + str r0, [r1, r2] + bgt .L_loop3 +.L_loop3_done: + ldr R0, =SystemInit blx R0 ldr R0,=main bx R0 -.endif .pool .cantunwind @@ -211,56 +216,34 @@ Default_Handler: .set \handler, Default_Handler .endm - IRQ DAC_IRQHandler - IRQ M0CORE_IRQHandler + IRQ RTC_IRQHandler + IRQ M4CORE_IRQHandler IRQ DMA_IRQHandler - IRQ EZH_IRQHandler - IRQ FLASH_EEPROM_IRQHandler + IRQ FLASHEEPROMAT_IRQHandler IRQ ETH_IRQHandler IRQ SDIO_IRQHandler IRQ LCD_IRQHandler IRQ USB0_IRQHandler IRQ USB1_IRQHandler IRQ SCT_IRQHandler - IRQ RIT_IRQHandler + IRQ RIT_OR_WWDT_IRQHandler IRQ TIMER0_IRQHandler - IRQ TIMER1_IRQHandler - IRQ TIMER2_IRQHandler + IRQ GINT1_IRQHandler + IRQ PIN_INT4_IRQHandler IRQ TIMER3_IRQHandler IRQ MCPWM_IRQHandler IRQ ADC0_IRQHandler - IRQ I2C0_IRQHandler - IRQ I2C1_IRQHandler - IRQ SPI_IRQHandler + IRQ I2C0_OR_I2C1_IRQHandler + IRQ SGPIO_IRQHandler + IRQ SPI_OR_DAC_IRQHandler IRQ ADC1_IRQHandler - IRQ SSP0_IRQHandler - IRQ SSP1_IRQHandler + IRQ SSP0_OR_SSP1_IRQHandler + IRQ EVENTROUTER_IRQHandler IRQ UART0_IRQHandler IRQ UART1_IRQHandler - IRQ UART2_IRQHandler + IRQ UART2_OR_C_CAN1_IRQHandler IRQ UART3_IRQHandler - IRQ I2S0_IRQHandler - IRQ I2S1_IRQHandler - IRQ SPIFI_IRQHandler - IRQ SGPIO_IRQHandler - IRQ GPIO0_IRQHandler - IRQ GPIO1_IRQHandler - IRQ GPIO2_IRQHandler - IRQ GPIO3_IRQHandler - IRQ GPIO4_IRQHandler - IRQ GPIO5_IRQHandler - IRQ GPIO6_IRQHandler - IRQ GPIO7_IRQHandler - IRQ GINT0_IRQHandler - IRQ GINT1_IRQHandler - IRQ EVRT_IRQHandler - IRQ CAN1_IRQHandler - IRQ VADC_IRQHandler - IRQ ATIMER_IRQHandler - IRQ RTC_IRQHandler - IRQ WDT_IRQHandler - IRQ M0s_IRQHandler - IRQ CAN0_IRQHandler - IRQ QEI_IRQHandler + IRQ I2S0_OR_I2S1_OR_QEI_IRQHandler + IRQ C_CAN0_IRQHandler .end diff --git a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/system_LPC43xx.c b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/system_LPC43xx.c index c51bd1c67e07b124137c33c1eb9ff5c4cd39849f..3309f50aaf5bdbd5d9d9560fd4d6781030258ea3 100644 --- a/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/system_LPC43xx.c +++ b/bsp/lpc43xx/Libraries/Device/NXP/LPC43xx/Source/Templates/system_LPC43xx.c @@ -869,6 +869,7 @@ void SystemCoreClockUpdate (void) { *----------------------------------------------------------------------------*/ void SystemInit (void) { +#ifdef BOOT_PROCESSOR #if (__FPU_USED == 1) SCB->CPACR |= ((3UL << 10*2) | /* set CP10 Full Access */ (3UL << 11*2) ); /* set CP11 Full Access */ @@ -880,9 +881,10 @@ void SystemInit (void) { /* Configure PLL0 and PLL1, connect CPU clock to selected clock source */ SetClock(); - /* Update SystemCoreClock variable */ - SystemCoreClockUpdate(); - /* Configure External Memory Controller */ SystemInit_ExtMemCtl (); +#endif + + /* Update SystemCoreClock variable */ + SystemCoreClockUpdate(); } diff --git a/bsp/lpc43xx/M0/SConscript b/bsp/lpc43xx/M0/SConscript index e2c31c0755375e697dd006a8965007c69c099cf1..8333973c014b4c104d26f73f2c4fdff8ec8acd61 100644 --- a/bsp/lpc43xx/M0/SConscript +++ b/bsp/lpc43xx/M0/SConscript @@ -2,12 +2,16 @@ from building import * cwd = GetCurrentDir() objs = [] -list = os.listdir(os.path.join(cwd, '..')) -for d in list: - if (d != 'M4' and d != 'M0'): - path = os.path.join(cwd, '..', d) - if os.path.isfile(os.path.join(path, 'SConscript')): - objs = objs + SConscript(os.path.join(path, 'SConscript')) +for d in os.listdir(os.path.join(cwd, '..')): + if d not in ('M0', 'M4'): + path = os.path.join('..', d, 'SConscript') + if os.path.isfile(os.path.join(cwd, path)): + objs = objs + SConscript(os.path.join(cwd, path)) + +for d in os.listdir(cwd): + p = os.path.join(d, 'SConscript'); + if os.path.isfile(os.path.join(cwd, p)): + objs = objs + SConscript(p) Return('objs') diff --git a/bsp/lpc43xx/M0/SConstruct b/bsp/lpc43xx/M0/SConstruct index f6f21f4ec453edfb116a0a177868f7742770feed..c7967d02f6fe07393fe306df24b7649fee150de9 100644 --- a/bsp/lpc43xx/M0/SConstruct +++ b/bsp/lpc43xx/M0/SConstruct @@ -5,7 +5,7 @@ import rtconfig if os.getenv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT') else: - RTT_ROOT = os.path.join(Dir('#').get_abspath(), '..', '..', 'rt-thread') + RTT_ROOT = os.path.join(Dir('#').get_abspath(), '..', '..', '..') sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] from building import * @@ -25,5 +25,23 @@ Export('rtconfig') # prepare building environment objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False) +if rtconfig.CROSS_TOOL == 'gcc': + import glob + # Remove the .o for M0 left on the drivers dir. + for i in glob.glob(GetCurrentDir() + '/../drivers/*.o'): + print 'RM %s' % i + os.unlink(i) + + if sys.platform.startswith('linux'): + import glob + ocwd = os.getcwdu() + res = os.system('cd ../Libraries/; find -name \*.o -exec rm {} \;') + os.chdir(ocwd) + else: + # Assume Windows. + ocwd = os.getcwdu() + print 'TODO: remove the object files in ../Libraries' + os.chdir(ocwd) + # do building DoBuilding(TARGET, objs) diff --git a/bsp/lpc43xx/applications/SConscript b/bsp/lpc43xx/M0/applications/SConscript similarity index 100% rename from bsp/lpc43xx/applications/SConscript rename to bsp/lpc43xx/M0/applications/SConscript diff --git a/bsp/lpc43xx/M0/applications/application.c b/bsp/lpc43xx/M0/applications/application.c new file mode 100644 index 0000000000000000000000000000000000000000..8e861873c8099c3db217c2451b7d3594f4d208ed --- /dev/null +++ b/bsp/lpc43xx/M0/applications/application.c @@ -0,0 +1,121 @@ +/* + * File : application.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2014, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-13 xiaonong port for lpc43xx + */ + +#include +#include +#include +#include "drv_led.h" + +#ifdef RT_USING_FINSH +#include +#include +#endif + +#ifdef RT_USING_LOGTRACE +#include +#endif + +#ifdef RT_USING_VBUS +#include +#endif + +/* thread phase init */ +void rt_init_thread_entry(void *parameter) +{ +#ifdef RT_USING_LOGTRACE + log_trace_init(); + log_trace_set_device(RT_CONSOLE_DEVICE_NAME); +#endif + +#ifdef RT_USING_FINSH + /* initialize finsh */ + finsh_system_init(); + finsh_set_device(RT_CONSOLE_DEVICE_NAME); +#endif + +#ifdef RT_USING_VBUS + rt_vbus_do_init(); +#endif +} + +/*the led thread*/ +ALIGN(RT_ALIGN_SIZE) +static rt_uint8_t led_stack[1024]; +static struct rt_thread led_thread; +static void led_thread_entry(void *parameter) +{ + rt_device_t led_dev; + rt_device_t vbus_dev; + rt_err_t err; + + rt_led_hw_init(); + + led_dev = rt_device_find("led"); + if (led_dev == RT_NULL) + { + rt_kprintf("can not find the led device\n"); + return; + } + + vbus_dev = rt_device_find("vecho"); + if (vbus_dev == RT_NULL) + { + rt_kprintf("can not find the vbus device\n"); + return; + } + + err = rt_device_open(vbus_dev, RT_DEVICE_OFLAG_RDWR); + if (err != RT_EOK) + { + rt_kprintf("open vbus failed: %d\n", err); + return; + } + + while (1) + { + rt_uint8_t led_value; + int len; + + len = rt_device_read(vbus_dev, 0, &led_value, sizeof(led_value)); + if (len <= 0) + { + rt_kprintf("vbus read err: %d, %d\n", len, rt_get_errno()); + } + + led_dev->write(led_dev, 1, &led_value, sizeof(led_value)); + } +} + +int rt_application_init(void) +{ + rt_thread_t tid; + rt_err_t result; + tid = rt_thread_create("init", + rt_init_thread_entry, RT_NULL, + 2048, 3, 20); + if (tid != RT_NULL) + rt_thread_startup(tid); + + /* init led thread */ + result = rt_thread_init(&led_thread, "led", + led_thread_entry, RT_NULL, + (rt_uint8_t *)&led_stack[0], sizeof(led_stack), + 20, 5); + if (result == RT_EOK) + { + rt_thread_startup(&led_thread); + } + return 0; +} + diff --git a/bsp/lpc43xx/M0/applications/board.c b/bsp/lpc43xx/M0/applications/board.c new file mode 100644 index 0000000000000000000000000000000000000000..000bd52f4019c76b779fcf9afe76f0bac30cd6f9 --- /dev/null +++ b/bsp/lpc43xx/M0/applications/board.c @@ -0,0 +1,67 @@ +/* + * File : board.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2014 RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-01-05 Bernard first implementation + * 2014-06-20 xiaonong ported to LPC43xx + */ + +#include +#include + +#include "board.h" +#include "drv_uart.h" + + +/** M0 does not have SysTick so we have to use RIT timer for it... */ +void RIT_OR_WWDT_IRQHandler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + if (LPC_RITIMER->CTRL & 0x01) + { + rt_tick_increase(); + LPC_RITIMER->CTRL |= 0x01; + } + + /* leave interrupt */ + rt_interrupt_leave(); +} + +extern void SystemCoreClockUpdate(void); + +/** + * This function will initial LPC43xx board. + */ +void rt_hw_board_init() +{ + SystemCoreClockUpdate(); + + /* Setup RIT timer. */ + LPC_RITIMER->MASK = 0; + LPC_RITIMER->COMPVAL = SystemCoreClock / RT_TICK_PER_SECOND; + /* Enable auto-clear. */ + LPC_RITIMER->CTRL |= 1 << 1; + /* Reset the counter as the counter is enabled after reset. */ + LPC_RITIMER->COUNTER = 0; + NVIC_SetPriority(M0_RITIMER_OR_WWDT_IRQn, (1 << __NVIC_PRIO_BITS) - 1); + NVIC_EnableIRQ(M0_RITIMER_OR_WWDT_IRQn); + + /* set pend exception priority */ + NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1); + + /* init uart device */ + rt_hw_uart_init(); + + /* setup the console device */ + rt_console_set_device(RT_CONSOLE_DEVICE_NAME); +} + diff --git a/bsp/lpc43xx/M0/applications/board.h b/bsp/lpc43xx/M0/applications/board.h new file mode 100644 index 0000000000000000000000000000000000000000..ee300eb73978785b5f8c5acbaca2d93324da9753 --- /dev/null +++ b/bsp/lpc43xx/M0/applications/board.h @@ -0,0 +1,59 @@ +/* + * File : board.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2009, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-09-22 Bernard add board.h to this bsp + * 2010-02-04 Magicoe add board.h to LPC176x bsp + * 2013-12-18 Bernard porting to LPC4088 bsp + */ + +#ifndef __BOARD_H__ +#define __BOARD_H__ + +#include "LPC43xx.h" +#include + +/* disable SDRAM in default */ +#ifndef LPC_EXT_SDRAM +#define LPC_EXT_SDRAM 0 +#endif + +// + +// +#define LPC_EXT_SDRAM_BEGIN 0xA0000000 +// +#define LPC_EXT_SDRAM_END 0xA2000000 + +// +// +//#define RT_USING_UART1 +// +//#define RT_USING_UART2 + +// + +#ifdef __CC_ARM +extern int Image$$RW_IRAM2$$ZI$$Limit; +#define HEAP_BEGIN ((void *)&Image$$RW_IRAM2$$ZI$$Limit) +#elif __ICCARM__ +#pragma section="HEAP" +#define HEAP_BEGIN (__segment_end("HEAP")) +#else +extern int __bss_end; +#define HEAP_BEGIN ((void *)&__bss_end) +#endif +#define HEAP_END (void*)(0x10080000 + 0x8000) + +void rt_hw_board_init(void); +int rt_hw_board_heap_init(void); +int rt_vbus_do_init(void); + +#endif diff --git a/bsp/lpc43xx/applications/startup.c b/bsp/lpc43xx/M0/applications/startup.c similarity index 100% rename from bsp/lpc43xx/applications/startup.c rename to bsp/lpc43xx/M0/applications/startup.c diff --git a/bsp/lpc43xx/M0/applications/vbus_conf.h b/bsp/lpc43xx/M0/applications/vbus_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..62bec83227049f2bc36f3b0f939d70dfc758ebe4 --- /dev/null +++ b/bsp/lpc43xx/M0/applications/vbus_conf.h @@ -0,0 +1,13 @@ +#ifndef __VBUS_CONF_H__ +#define __VBUS_CONF_H__ + +/* Number of blocks in VBus. The total size of VBus is + * RT_VMM_RB_BLK_NR * 64byte * 2. */ +#define RT_VMM_RB_BLK_NR 20 + +/* We don't use the IRQ number to trigger IRQ in this BSP. */ +#define RT_VBUS_GUEST_VIRQ 0 +#define RT_VBUS_HOST_VIRQ 0 + +#endif /* end of include guard: __VBUS_CONF_H__ */ + diff --git a/bsp/lpc43xx/M0/applications/vbus_drv.c b/bsp/lpc43xx/M0/applications/vbus_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..24d7f19b580151c5e90f6005ed19b27fc25e6d11 --- /dev/null +++ b/bsp/lpc43xx/M0/applications/vbus_drv.c @@ -0,0 +1,86 @@ +/* + * VMM Bus Driver + * + * COPYRIGHT (C) 2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-07 Grissiom add comment + */ + +#include + +#ifdef RT_USING_VBUS +#include +#include +#include + +struct rt_vbus_ring rt_vbus_rings[2] SECTION("vbus_ring"); + +int rt_vbus_do_init(void) +{ + return rt_vbus_init(&rt_vbus_rings[1], &rt_vbus_rings[0]); +} +INIT_COMPONENT_EXPORT(rt_vbus_do_init); + +int rt_vbus_hw_init(void) +{ + NVIC_ClearPendingIRQ(M0_M4CORE_IRQn); + NVIC_EnableIRQ(M0_M4CORE_IRQn); + return 0; +} + +void M4CORE_IRQHandler(void) +{ + LPC_CREG->M4TXEVENT = 0; + rt_vbus_isr(M0_M4CORE_IRQn, RT_NULL); +} + +int rt_vbus_hw_eoi(int irqnr, void *param) +{ + /* Nothing to do here as we cleared the interrupt in IRQHandler. */ + return 0; +} + +struct rt_vbus_dev rt_vbus_chn_devx[] = { + { + .req = + { + .prio = 30, + .name = "vecho", + .is_server = 0, + .recv_wm.low = RT_VMM_RB_BLK_NR / 3, + .recv_wm.high = RT_VMM_RB_BLK_NR * 2 / 3, + .post_wm.low = RT_VMM_RB_BLK_NR / 3, + .post_wm.high = RT_VMM_RB_BLK_NR * 2 / 3, + } + }, + { + .req = + { + .name = RT_NULL, + } + }, +}; + +#endif /* RT_USING_VBUS */ + diff --git a/bsp/lpc43xx/M0/applications/vbus_hw.h b/bsp/lpc43xx/M0/applications/vbus_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..b88586a112f08933633b8cb0bd28125c189f7aa4 --- /dev/null +++ b/bsp/lpc43xx/M0/applications/vbus_hw.h @@ -0,0 +1,53 @@ +/* + * VMM Bus + * + * COPYRIGHT (C) 2015, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-07 Grissiom init commit + */ + +#include +#include + +rt_inline void rt_vbus_tick(unsigned int target_cpu, unsigned int irqnr) +{ + __SEV(); +} + +/* Read memory barrier. */ +rt_inline void rt_vbus_smp_rmb(void) +{ + __DMB(); +} + +/* Write memory barrier. */ +rt_inline void rt_vbus_smp_wmb(void) +{ + __DSB(); +} + +/* General memory barrier. */ +rt_inline void rt_vbus_smp_mb(void) +{ + __DSB(); +} diff --git a/bsp/lpc43xx/M0/rtconfig.h b/bsp/lpc43xx/M0/rtconfig.h index 84fc28028c140a3eea4cf627bbe05421977ff9ca..77846191fc56628d5687cc685d4820c2fbe727b6 100644 --- a/bsp/lpc43xx/M0/rtconfig.h +++ b/bsp/lpc43xx/M0/rtconfig.h @@ -24,6 +24,7 @@ #define RT_DEBUG // #define RT_DEBUG_INIT 0 +//#define RT_DEBUG_SCHEDULER 1 // // #define RT_THREAD_DEBUG // @@ -33,7 +34,7 @@ // #define RT_USING_HOOK //
-#define RT_USING_TIMER_SOFT +//#define RT_USING_TIMER_SOFT // #define RT_TIMER_THREAD_PRIO 4 // @@ -96,6 +97,7 @@ #define RT_CONSOLEBUF_SIZE 128 // #define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_USING_UART0 //
// @@ -222,7 +224,8 @@ #define RT_LWIP_MSKADDR3 0 // - +#define RT_USING_VBUS +#define RT_USING_LOGTRACE // diff --git a/bsp/lpc43xx/M0/rtconfig.py b/bsp/lpc43xx/M0/rtconfig.py index 5eef1d3ab83ecc5e6d6c8b7f6505ed2ff839869f..e998c27fe1eae0aa49aca819234865b2cb42a5ea 100644 --- a/bsp/lpc43xx/M0/rtconfig.py +++ b/bsp/lpc43xx/M0/rtconfig.py @@ -2,15 +2,11 @@ import os # core to be use USE_CORE = 'CORE_M0' -#USE_CORE = 'CORE_M4' # toolchains options ARCH='arm' -if USE_CORE == 'CORE_M4': - CPU = 'cortex-m4' -else: - CPU = 'cortex-m0' +CPU = 'cortex-m0' CROSS_TOOL='keil' @@ -35,7 +31,7 @@ if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') # -BUILD = 'release' +BUILD = 'debug' if PLATFORM == 'gcc': # toolchains @@ -48,23 +44,24 @@ if PLATFORM == 'gcc': SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' - DEVICE = ' -mcpu=' + CPU + ' -mthumb -ffunction-sections -fdata-sections' - if USE_CORE == 'CORE_M4': - DEVICE += ' -mfpu=fpv4-sp-d16 -mfloat-abi=softfp' - CFLAGS = DEVICE + DEVICE = ' -mthumb -mcpu=cortex-m0 -ffunction-sections -fdata-sections -Wall' + CFLAGS = DEVICE AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb ' - LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread-lpc43xx.map,-cref,-u,Reset_Handler -T rtthread-lpc43xx_spifi.ld' + LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread-lpc43xx.map,-cref,-u,Reset_Handler -T rtthread-lpc43xx.ld' CPATH = '' LPATH = '' + CFLAGS += ' -gdwarf-2' + AFLAGS += ' -gdwarf-2' if BUILD == 'debug': - CFLAGS += ' -O0 -gdwarf-2' - AFLAGS += ' -gdwarf-2' + CFLAGS += ' -O0' else: CFLAGS += ' -O2' - POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' + POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' +\ + SIZE + ' $TARGET \n' +\ + '../bin2C.py rtthread.bin ../M4/applications/M0_CODE.h' elif PLATFORM == 'armcc': # toolchains diff --git a/bsp/lpc43xx/M0/rtthread-lpc43xx.ld b/bsp/lpc43xx/M0/rtthread-lpc43xx.ld new file mode 100644 index 0000000000000000000000000000000000000000..e8ef2fe4900e782722ddc7d1be6745699d1f0886 --- /dev/null +++ b/bsp/lpc43xx/M0/rtthread-lpc43xx.ld @@ -0,0 +1,139 @@ +/* + * linker script for LPC43xx SPIFI (4Mb NorFlash, 32kB SRAM ) with GNU ld + * yiyue.fang 2012-04-14 + */ + +/* Program Entry, set to mark it as "used" and avoid gc */ +MEMORY +{ + CODE (rx) : ORIGIN = 0x1B000000, LENGTH = 0x00080000 + DATA (rw) : ORIGIN = 0x10080000, LENGTH = 0x00008000 + AHBRAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000 +} +ENTRY(Reset_Handler) +_system_stack_size = 0x200; + +SECTIONS +{ + .text : + { + . = ALIGN(4); + KEEP(*(.interrupt_vector)) /* Startup code */ + . = ALIGN(4); + *(.text) /* remaining code */ + *(.text.*) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t*) + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + . = ALIGN(4); + _etext = .; + } > CODE = 0 + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + + /* This is used by the startup in order to initialize the .data secion */ + _sidata = .; + } > CODE + __exidx_end = .; + + /* .data section which is used for initialized data */ + + .data : AT (_sidata) + { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _sdata = . ; + + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _edata = . ; + } >DATA + + .stack : + { + . = . + _system_stack_size; + . = ALIGN(4); + _estack = .; + } >DATA + + __bss_start = .; + .bss : + { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; + + *(.bss) + *(.bss.*) + *(COMMON) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _ebss = . ; + *(.bss.init) + } > DATA + __bss_end = .; + + .vbus_ring (NOLOAD) : + { + *(vbus_ring) + } > AHBRAM + + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/bsp/lpc43xx/M0/rtthread_lpc43xx.sct b/bsp/lpc43xx/M0/rtthread_lpc43xx.sct new file mode 100644 index 0000000000000000000000000000000000000000..d0fd443a852cf0d5bc78dc5acca279395008ba02 --- /dev/null +++ b/bsp/lpc43xx/M0/rtthread_lpc43xx.sct @@ -0,0 +1,18 @@ +; ************************************************************* +; *** Scatter-Loading Description File generated by uVision *** +; ************************************************************* + +LR_IROM2 0x1B000000 0x00080000 { ; load region size_region + ER_IROM2 0x1B000000 0x00080000 { ; load address = execution address + *.o (RESET, +First) + *(InRoot$$Sections) + .ANY (+RO) + } + RW_IRAM2 0x10080000 0x00008000 { ; RW data + .ANY (+RW +ZI) + } + RW_AHBRAM 0x20000000 0x00010000 { ; RW data + * (vbus_ring) + } +} + diff --git a/bsp/lpc43xx/M0/template.uvproj b/bsp/lpc43xx/M0/template.uvproj index 95f6c36a2bfa1237d256facd624aa9ff691767b4..fc50dbac3e1e5d8ebdd6cf575f803945699f22e6 100644 --- a/bsp/lpc43xx/M0/template.uvproj +++ b/bsp/lpc43xx/M0/template.uvproj @@ -12,13 +12,13 @@ ARM-ADS - LPC4357 - NXP (founded by Philips) - IRAM(0x10000000-0x10007FFF) IRAM2(0x20000000-0x2000FFFF) IROM(0x1A000000-0x1A07FFFF) IROM2(0x1B000000-0x1B07FFFF) CLOCK(12000000) CPUTYPE("Cortex-M4") FPU2 + LPC4357 CM0 + NXP + CLOCK(12000000) CPUTYPE("Cortex-M0") - "STARTUP\NXP\LPC43xx\startup_LPC43xx.s" ("NXP LPC43xx Startup Code") - UL2CM3(-O975 -S0 -C0 -FO7 -FD10000000 -FC800 -FN2 -FF0LPC18xx43xx_512_BA -FS01A000000 -FL080000 -FF1LPC18xx43xx_512_BB -FS11B000000 -FL180000) - 6414 + "STARTUP\NXP\LPC43xx\startup_LPC43xx_M0.s" ("NXP LPC43xx CM0 Startup Code") + UL2CM3(-O910 -S8 -C1 -FO7 -FD10000000 -FC800 -FN0) + 6917 LPC43xx.H @@ -26,10 +26,11 @@ - + -DCORE_M0 SFD\NXP\LPC43xx\LPC43xx.SFR + 0 0 @@ -73,10 +74,10 @@ 0 - 0 - 0 - - + 1 + 1 + fromelf --bin !L --output rtthread.bin + C:\Python27\python.exe ..\bin2C.py rtthread.bin ..\M4\applications\M0_CODE.h 0 0 @@ -208,10 +209,10 @@ 1 0 0 - 1 + 2 1 1 - 1 + 16 1 0 0 @@ -224,11 +225,11 @@ 0 0 0 - 1 + 0 0 0 0 - 0 + 1 0 0 0 @@ -338,7 +339,7 @@ 1 0 0 - 0 + 1 0 0 0 @@ -371,7 +372,7 @@ - 1 + 0 0 0 0 @@ -379,390 +380,8 @@ 0 0x14000000 0x10000000 - - - - - - - - - - - - LPC43xx RAM - 0x4 - ARM-ADS - - - LPC4357 - NXP (founded by Philips) - IRAM(0x10000000-0x10007FFF) IRAM2(0x20000000-0x2000FFFF) IROM(0x1A000000-0x1A07FFFF) IROM2(0x1B000000-0x1B07FFFF) CLOCK(12000000) CPUTYPE("Cortex-M4") FPU2 - - "STARTUP\NXP\LPC43xx\startup_LPC43xx.s" ("NXP LPC43xx Startup Code") - UL2CM3(-O975 -S0 -C0 -FO7 -FD10000000 -FC800 -FN2 -FF0LPC18xx43xx_512_BA -FS01A000000 -FL080000 -FF1LPC18xx43xx_512_BB -FS11B000000 -FL180000) - 6414 - LPC43xx.H - - - - - - - - - - SFD\NXP\LPC43xx\LPC43xx.SFR - 0 - - - - NXP\LPC43xx\ - NXP\LPC43xx\ - - 0 - 0 - 0 - 0 - 1 - - .\build\ - rtthread_lpc43xx - 1 - 0 - 0 - 1 - 1 - .\build\ - 1 - 0 - 0 - - 0 - 0 - - - 0 - 0 - 0 - 0 - - - 0 - 0 - - - 0 - 0 - - - 0 - 0 - - - 0 - 0 - - 0 - - - - 0 - 0 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 3 - - - - - SARMCM3.DLL - -MPU - DCM.DLL - -pCM4 - SARMCM3.DLL - -MPU - TCM.DLL - -pCM4 - - - - 1 - 0 - 0 - 0 - 16 - - - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - - - 1 - 0 - 0 - 1 - 1 - 0 - 0 - 1 - 0 - - 0 - 1 - - - - - - - - - - - - - .\Dbg_RAM.ini - BIN\UL2CM3.DLL - - - - - 1 - 1 - 0 - 1 - 1 - 4096 - - 1 - BIN\UL2CM3.DLL - "" () - - - - - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - 1 - 1 - 0 - 1 - 1 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - 0 - "Cortex-M4" - - 0 - 0 - 0 - 1 - 1 - 0 - 0 - 1 - 1 - 1 - 8 - 1 - 0 - 0 - 3 - 3 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x10000000 - 0x8000 - - - 1 - 0x1a000000 - 0x80000 - - - 0 - 0x0 - 0x0 - - - 1 - 0x0 - 0x0 - - - 1 - 0x0 - 0x0 - - - 1 - 0x0 - 0x0 - - - 1 - 0x1a000000 - 0x80000 - - - 1 - 0x1b000000 - 0x80000 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x10000000 - 0x8000 - - - 0 - 0x20000000 - 0x10000 - - - - - - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - NO_CRP - - - - - - 1 - 0 - 0 - 0 - 1 - 0 - 0x10000000 - 0x20000000 - + + .\rtthread_lpc43xx.sct @@ -773,5 +392,4 @@ - diff --git a/bsp/lpc43xx/M0/vbus_local_conf.h b/bsp/lpc43xx/M0/vbus_local_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..571c51e6129f9c05ddad57b2819858550ae534da --- /dev/null +++ b/bsp/lpc43xx/M0/vbus_local_conf.h @@ -0,0 +1,8 @@ +#ifndef __VBUS_LOCAL_CONF_H__ +#define __VBUS_LOCAL_CONF_H__ + +#define RT_VBUS_USING_FLOW_CONTROL + +#define RT_VBUS_USING_TESTS + +#endif /* end of include guard: __VBUS_LOCAL_CONF_H__ */ diff --git a/bsp/lpc43xx/M4/SConscript b/bsp/lpc43xx/M4/SConscript index e2c31c0755375e697dd006a8965007c69c099cf1..8333973c014b4c104d26f73f2c4fdff8ec8acd61 100644 --- a/bsp/lpc43xx/M4/SConscript +++ b/bsp/lpc43xx/M4/SConscript @@ -2,12 +2,16 @@ from building import * cwd = GetCurrentDir() objs = [] -list = os.listdir(os.path.join(cwd, '..')) -for d in list: - if (d != 'M4' and d != 'M0'): - path = os.path.join(cwd, '..', d) - if os.path.isfile(os.path.join(path, 'SConscript')): - objs = objs + SConscript(os.path.join(path, 'SConscript')) +for d in os.listdir(os.path.join(cwd, '..')): + if d not in ('M0', 'M4'): + path = os.path.join('..', d, 'SConscript') + if os.path.isfile(os.path.join(cwd, path)): + objs = objs + SConscript(os.path.join(cwd, path)) + +for d in os.listdir(cwd): + p = os.path.join(d, 'SConscript'); + if os.path.isfile(os.path.join(cwd, p)): + objs = objs + SConscript(p) Return('objs') diff --git a/bsp/lpc43xx/M4/SConstruct b/bsp/lpc43xx/M4/SConstruct index f6f21f4ec453edfb116a0a177868f7742770feed..7b02b732d48f27beb23e9e4da155ea95f9f35828 100644 --- a/bsp/lpc43xx/M4/SConstruct +++ b/bsp/lpc43xx/M4/SConstruct @@ -5,12 +5,12 @@ import rtconfig if os.getenv('RTT_ROOT'): RTT_ROOT = os.getenv('RTT_ROOT') else: - RTT_ROOT = os.path.join(Dir('#').get_abspath(), '..', '..', 'rt-thread') + RTT_ROOT = os.path.join(Dir('#').get_abspath(), '..', '..', '..') sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] from building import * -TARGET = 'rtthread-lpc40xx.' + rtconfig.TARGET_EXT +TARGET = 'build/rtthread_lpc43xx.' + rtconfig.TARGET_EXT env = Environment(tools = ['mingw'], AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, @@ -25,5 +25,30 @@ Export('rtconfig') # prepare building environment objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False) +if rtconfig.CROSS_TOOL == 'gcc': + print 'build M0 code first' + if sys.platform.startswith('linux'): + import glob + ocwd = os.getcwdu() + os.chdir('../M0') + res = os.system('scons') + if res: + print 'build M0 exit with code %d\n' % res + sys.exit(res) + os.chdir(ocwd) + res = os.system('cd ../Libraries/; find -name \*.o -exec rm {} \;') + os.chdir(ocwd) + else: + # Assume Windows. + ocwd = os.getcwdu() + os.chdir('..\M0') + os.system('scons.bat') + os.chdir(ocwd) + + # Remove the .o for M0 left on the drivers dir. + for i in glob.glob(GetCurrentDir() + '/../drivers/*.o'): + print 'RM %s' % i + os.unlink(i) + # do building DoBuilding(TARGET, objs) diff --git a/bsp/lpc43xx/M4/applications/SConscript b/bsp/lpc43xx/M4/applications/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..773b8d04229cc157c16695e497aba2b4dcb7a994 --- /dev/null +++ b/bsp/lpc43xx/M4/applications/SConscript @@ -0,0 +1,13 @@ +Import('RTT_ROOT') +Import('rtconfig') +from building import * + +cwd = os.path.join(str(Dir('#')), 'applications') +src = Glob('*.c') +CPPPATH = [cwd, str(Dir('#'))] + +group = DefineGroup('Applications', src, + depend = [''], CPPPATH = CPPPATH, + CPPDEFINES = ['BOOT_PROCESSOR']) + +Return('group') diff --git a/bsp/lpc43xx/M4/applications/application.c b/bsp/lpc43xx/M4/applications/application.c new file mode 100644 index 0000000000000000000000000000000000000000..6575991895c6d73085541b402683bbfe9d3b3848 --- /dev/null +++ b/bsp/lpc43xx/M4/applications/application.c @@ -0,0 +1,156 @@ +/* + * File : application.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2014, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2014-07-13 xiaonong port for lpc43xx + */ + +#include +#include +#include +#include "drv_led.h" + +#ifdef RT_USING_FINSH +#include +#include +#endif + +#ifdef RT_USING_LOGTRACE +#include +#endif + +#ifdef RT_USING_VBUS +#include +#endif + +static const unsigned char _M0_CODE[] SECTION("M0_CODE") = { +#include "M0_CODE.h" +}; + +static void _boot_M0(void) +{ + volatile uint32_t u32REG, u32Val; + + LPC_CREG->M0APPMEMMAP = (uint32_t)&_M0_CODE[0]; + + // Release Slave from reset, first read status + u32REG = LPC_RGU->RESET_ACTIVE_STATUS1; + + // If the M0 is being held in reset, release it... + // 1 = no reset, 0 = reset + while(!(u32REG & (1u << 24))) + { + u32Val = (~(u32REG) & (~(1 << 24))); + LPC_RGU->RESET_CTRL1 = u32Val; + u32REG = LPC_RGU->RESET_ACTIVE_STATUS1; + } + + rt_kprintf("M0 boot to %p\n", &_M0_CODE[0]); +} + +/* thread phase init */ +void rt_init_thread_entry(void *parameter) +{ + /* + *register unsigned int _msp __asm("msp"); + *register unsigned int _psp __asm("psp"); + *rt_kprintf("msp@ %p, psp@ %p\n", _msp, _psp); + */ +#ifdef RT_USING_LOGTRACE + log_trace_init(); + log_trace_set_device(RT_CONSOLE_DEVICE_NAME); +#endif + +#ifdef RT_USING_FINSH + /* initialize finsh */ + finsh_system_init(); + finsh_set_device(RT_CONSOLE_DEVICE_NAME); +#endif + +#ifdef RT_USING_VBUS + rt_vbus_do_init(); +#endif + + _boot_M0(); +} + +/*the led thread*/ +ALIGN(RT_ALIGN_SIZE) +static rt_uint8_t led_stack[ 512 ]; +static struct rt_thread led_thread; +static void led_thread_entry(void *parameter) +{ + rt_uint8_t led_value; + rt_device_t led_dev; + rt_device_t vbus_dev; + rt_err_t err; + + rt_led_hw_init(); + + led_dev = rt_device_find("led"); + if (led_dev == RT_NULL) + { + rt_kprintf("can not find the led device\n"); + return; + } + + vbus_dev = rt_device_find("vecho"); + if (vbus_dev == RT_NULL) + { + rt_kprintf("can not find the vbus device\n"); + return; + } + + err = rt_device_open(vbus_dev, RT_DEVICE_OFLAG_RDWR); + if (err != RT_EOK) + { + rt_kprintf("open vbus failed: %d\n", err); + return; + } + + led_value = 0; + while (1) + { + int len; + + led_dev->write(led_dev, 0, &led_value, sizeof(led_value)); + + led_value = !led_value; + len = rt_device_write(vbus_dev, 0, &led_value, sizeof(led_value)); + if (len <= 0) + { + rt_kprintf("vbus write err: %d, %d\n", len, rt_get_errno()); + } + + rt_thread_delay(1000); + } +} + +int rt_application_init(void) +{ + rt_thread_t tid; + rt_err_t result; + tid = rt_thread_create("init", + rt_init_thread_entry, RT_NULL, + 2048, 3, 20); + if (tid != RT_NULL) + rt_thread_startup(tid); + + /* init led thread */ + result = rt_thread_init(&led_thread, "led", + led_thread_entry, RT_NULL, + (rt_uint8_t *)&led_stack[0], sizeof(led_stack), + 20, 5); + if (result == RT_EOK) + { + rt_thread_startup(&led_thread); + } + return 0; +} diff --git a/bsp/lpc43xx/drivers/board.c b/bsp/lpc43xx/M4/applications/board.c similarity index 87% rename from bsp/lpc43xx/drivers/board.c rename to bsp/lpc43xx/M4/applications/board.c index 421298c19ea5e06e6d7e1d5d8056fe118f616137..dc0859f666f7c1462356aad02a70ac91a118726c 100644 --- a/bsp/lpc43xx/drivers/board.c +++ b/bsp/lpc43xx/M4/applications/board.c @@ -43,20 +43,19 @@ void rt_hw_board_init() { #ifdef CORE_M4 /* NVIC Configuration */ -#define NVIC_VTOR_MASK 0x3FFFFF80 #ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x10000000 */ - SCB->VTOR = (0x10000000 & NVIC_VTOR_MASK); + SCB->VTOR = 0x10000000; #else /* VECT_TAB_FLASH */ /* Set the Vector Table base location at 0x00000000 */ - SCB->VTOR = (0x00000000 & NVIC_VTOR_MASK); + SCB->VTOR = 0x1A000000; #endif #endif /* update the core clock */ SystemCoreClockUpdate(); /* init systick */ - SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND - 1); + SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); /* set pend exception priority */ NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1); diff --git a/bsp/lpc43xx/drivers/board.h b/bsp/lpc43xx/M4/applications/board.h similarity index 98% rename from bsp/lpc43xx/drivers/board.h rename to bsp/lpc43xx/M4/applications/board.h index 393dc30c91bd6ffe44f000c2dbe154417887a9c2..299404a368513bbf9a7aaed4a506e016bdd5a5e3 100644 --- a/bsp/lpc43xx/drivers/board.h +++ b/bsp/lpc43xx/M4/applications/board.h @@ -33,7 +33,6 @@ #define LPC_EXT_SDRAM_END 0xA2000000 // -#define RT_USING_UART0 // //#define RT_USING_UART1 // @@ -55,6 +54,6 @@ extern int __bss_end; void rt_hw_board_init(void); int rt_hw_board_heap_init(void); - +int rt_vbus_do_init(void); #endif diff --git a/bsp/lpc43xx/M4/applications/startup.c b/bsp/lpc43xx/M4/applications/startup.c new file mode 100644 index 0000000000000000000000000000000000000000..f6cf534b03d9110f7a362fc0ab94a11977d5062d --- /dev/null +++ b/bsp/lpc43xx/M4/applications/startup.c @@ -0,0 +1,74 @@ +/* + * File : startup.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2009, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-01-05 Bernard first implementation + * 2014-07-13 xiaonong for LPC43xx + */ + +#include +#include + +#include "board.h" + +extern int rt_application_init(void); + +/** + * This function will startup RT-Thread RTOS. + */ +void rtthread_startup(void) +{ + /* initialize board */ + rt_hw_board_init(); + + /* show version */ + rt_show_version(); + +#ifdef RT_USING_HEAP +#if LPC_EXT_SDRAM + rt_system_heap_init((void *)LPC_EXT_SDRAM_BEGIN, (void *)LPC_EXT_SDRAM_END); + sram_init(); +#else + rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END); +#endif +#endif + + /* initialize scheduler system */ + rt_system_scheduler_init(); + + /* initialize system timer*/ + rt_system_timer_init(); + + /* initialize application */ + rt_application_init(); + + /* initialize timer thread */ + rt_system_timer_thread_init(); + + /* initialize idle thread */ + rt_thread_idle_init(); + + /* start scheduler */ + rt_system_scheduler_start(); + + /* never reach here */ + return ; +} + +int main(void) +{ + /* disable interrupt first */ + rt_hw_interrupt_disable(); + + /* startup RT-Thread RTOS */ + rtthread_startup(); + + return 0; +} diff --git a/bsp/lpc43xx/M4/applications/vbus_conf.h b/bsp/lpc43xx/M4/applications/vbus_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..62bec83227049f2bc36f3b0f939d70dfc758ebe4 --- /dev/null +++ b/bsp/lpc43xx/M4/applications/vbus_conf.h @@ -0,0 +1,13 @@ +#ifndef __VBUS_CONF_H__ +#define __VBUS_CONF_H__ + +/* Number of blocks in VBus. The total size of VBus is + * RT_VMM_RB_BLK_NR * 64byte * 2. */ +#define RT_VMM_RB_BLK_NR 20 + +/* We don't use the IRQ number to trigger IRQ in this BSP. */ +#define RT_VBUS_GUEST_VIRQ 0 +#define RT_VBUS_HOST_VIRQ 0 + +#endif /* end of include guard: __VBUS_CONF_H__ */ + diff --git a/bsp/lpc43xx/M4/applications/vbus_drv.c b/bsp/lpc43xx/M4/applications/vbus_drv.c new file mode 100644 index 0000000000000000000000000000000000000000..872de86504d0486dfc627dbe3ad7c0bad3ed1232 --- /dev/null +++ b/bsp/lpc43xx/M4/applications/vbus_drv.c @@ -0,0 +1,86 @@ +/* + * VMM Bus Driver + * + * COPYRIGHT (C) 2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-07 Grissiom add comment + */ + +#include + +#ifdef RT_USING_VBUS +#include +#include +#include + +struct rt_vbus_ring rt_vbus_rings[2] SECTION("vbus_ring"); + +int rt_vbus_do_init(void) +{ + return rt_vbus_init(&rt_vbus_rings[0], &rt_vbus_rings[1]); +} +INIT_COMPONENT_EXPORT(rt_vbus_do_init); + +int rt_vbus_hw_init(void) +{ + NVIC_ClearPendingIRQ(M0CORE_IRQn); + NVIC_EnableIRQ(M0CORE_IRQn); + return 0; +} + +void M0CORE_IRQHandler(void) +{ + LPC_CREG->M0TXEVENT = 0; + rt_vbus_isr(M0CORE_IRQn, RT_NULL); +} + +int rt_vbus_hw_eoi(int irqnr, void *param) +{ + /* Nothing to do here as we cleared the interrupt in IRQHandler. */ + return 0; +} + +struct rt_vbus_dev rt_vbus_chn_devx[] = { + { + .req = + { + .prio = 30, + .name = "vecho", + .is_server = 1, + .recv_wm.low = RT_VMM_RB_BLK_NR / 3, + .recv_wm.high = RT_VMM_RB_BLK_NR * 2 / 3, + .post_wm.low = RT_VMM_RB_BLK_NR / 3, + .post_wm.high = RT_VMM_RB_BLK_NR * 2 / 3, + } + }, + { + .req = + { + .name = RT_NULL, + } + }, +}; + +#endif /* RT_USING_VBUS */ + diff --git a/bsp/lpc43xx/M4/applications/vbus_hw.h b/bsp/lpc43xx/M4/applications/vbus_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..b88586a112f08933633b8cb0bd28125c189f7aa4 --- /dev/null +++ b/bsp/lpc43xx/M4/applications/vbus_hw.h @@ -0,0 +1,53 @@ +/* + * VMM Bus + * + * COPYRIGHT (C) 2015, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-07 Grissiom init commit + */ + +#include +#include + +rt_inline void rt_vbus_tick(unsigned int target_cpu, unsigned int irqnr) +{ + __SEV(); +} + +/* Read memory barrier. */ +rt_inline void rt_vbus_smp_rmb(void) +{ + __DMB(); +} + +/* Write memory barrier. */ +rt_inline void rt_vbus_smp_wmb(void) +{ + __DSB(); +} + +/* General memory barrier. */ +rt_inline void rt_vbus_smp_mb(void) +{ + __DSB(); +} diff --git a/bsp/lpc43xx/M4/rtconfig.h b/bsp/lpc43xx/M4/rtconfig.h index 84fc28028c140a3eea4cf627bbe05421977ff9ca..31854ca2fccef0029f556435a7fe235fa3ca5792 100644 --- a/bsp/lpc43xx/M4/rtconfig.h +++ b/bsp/lpc43xx/M4/rtconfig.h @@ -95,7 +95,8 @@ // #define RT_CONSOLEBUF_SIZE 128 // -#define RT_CONSOLE_DEVICE_NAME "uart0" +#define RT_CONSOLE_DEVICE_NAME "uart3" +#define RT_USING_UART3 // // @@ -222,7 +223,8 @@ #define RT_LWIP_MSKADDR3 0 // - +#define RT_USING_VBUS +#define RT_USING_LOGTRACE // diff --git a/bsp/lpc43xx/M4/rtconfig.py b/bsp/lpc43xx/M4/rtconfig.py index b19c3901600abfece069b117c2e675ef94df6818..1cbaacf65061c32114b8fafa472ca5b94c77625e 100644 --- a/bsp/lpc43xx/M4/rtconfig.py +++ b/bsp/lpc43xx/M4/rtconfig.py @@ -35,7 +35,7 @@ if os.getenv('RTT_EXEC_PATH'): EXEC_PATH = os.getenv('RTT_EXEC_PATH') # -BUILD = 'release' +BUILD = 'debug' if PLATFORM == 'gcc': # toolchains @@ -44,23 +44,24 @@ if PLATFORM == 'gcc': AS = PREFIX + 'gcc' AR = PREFIX + 'ar' LINK = PREFIX + 'gcc' - TARGET_EXT = 'elf' + TARGET_EXT = 'axf' SIZE = PREFIX + 'size' OBJDUMP = PREFIX + 'objdump' OBJCPY = PREFIX + 'objcopy' - DEVICE = ' -mcpu=' + CPU + ' -mthumb -ffunction-sections -fdata-sections' + DEVICE = ' -mcpu=' + CPU + ' -mthumb -ffunction-sections -fdata-sections -Wall' if USE_CORE == 'CORE_M4': DEVICE += ' -mfpu=fpv4-sp-d16 -mfloat-abi=softfp' CFLAGS = DEVICE AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb ' - LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread-lpc43xx.map,-cref,-u,Reset_Handler -T rtthread-lpc43xx_spifi.ld' + LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread-lpc43xx.map,-cref,-u,Reset_Handler -T rtthread-lpc43xx.ld' CPATH = '' LPATH = '' + CFLAGS += ' -gdwarf-2' + AFLAGS += ' -gdwarf-2' if BUILD == 'debug': - CFLAGS += ' -O0 -gdwarf-2' - AFLAGS += ' -gdwarf-2' + CFLAGS += ' -O0' else: CFLAGS += ' -O2' diff --git a/bsp/lpc43xx/M4/rtthread-lpc43xx.ld b/bsp/lpc43xx/M4/rtthread-lpc43xx.ld new file mode 100644 index 0000000000000000000000000000000000000000..63057abc40613d295ed3426ac6f8b15bdbf25a00 --- /dev/null +++ b/bsp/lpc43xx/M4/rtthread-lpc43xx.ld @@ -0,0 +1,147 @@ +/* + * linker script for LPC43xx SPIFI (4Mb NorFlash, 32kB SRAM ) with GNU ld + * yiyue.fang 2012-04-14 + */ + +/* Program Entry, set to mark it as "used" and avoid gc */ +MEMORY +{ + CODE (rx) : ORIGIN = 0x1A000000, LENGTH = 0x00080000 + M0CODE (rx) : ORIGIN = 0x1B000000, LENGTH = 0x00080000 + DATA (rw) : ORIGIN = 0x10000000, LENGTH = 0x00008000 + AHBRAM (rw) : ORIGIN = 0x20000000, LENGTH = 0x00010000 +} +ENTRY(Reset_Handler) +_system_stack_size = 0x200; + +SECTIONS +{ + .text : + { + . = ALIGN(4); + KEEP(*(.interrupt_vector)) /* Startup code */ + . = ALIGN(4); + *(.text) /* remaining code */ + *(.text.*) /* remaining code */ + *(.rodata) /* read-only data (constants) */ + *(.rodata*) + *(.glue_7) + *(.glue_7t) + *(.gnu.linkonce.t*) + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + . = ALIGN(4); + _etext = .; + } > CODE = 0 + + /* .ARM.exidx is sorted, so has to go in its own output section. */ + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + + /* This is used by the startup in order to initialize the .data secion */ + _sidata = .; + } > CODE + __exidx_end = .; + + /* .data section which is used for initialized data */ + + .data : AT (_sidata) + { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _sdata = . ; + + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .data secion */ + _edata = . ; + } >DATA + + . = _edata ; + .stack : + { + . = . + _system_stack_size; + . = ALIGN(4); + _estack = .; + } >DATA + + __bss_start = .; + .bss : + { + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; + + *(.bss) + *(.bss.*) + *(COMMON) + + . = ALIGN(4); + /* This is used by the startup in order to initialize the .bss secion */ + _ebss = . ; + *(.bss.init) + } > DATA + __bss_end = .; + + .vbus_ring (NOLOAD) : + { + *(vbus_ring) + } > AHBRAM + + + .text.M0CODE : + { + *(M0_CODE) + } > M0CODE = 0 + + _end = .; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + * Symbols in the DWARF debugging sections are relative to the beginning + * of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } +} diff --git a/bsp/lpc43xx/M4/rtthread_lpc43xx.sct b/bsp/lpc43xx/M4/rtthread_lpc43xx.sct new file mode 100644 index 0000000000000000000000000000000000000000..238ca28c6e93e40bb4df605557035122124a7ac2 --- /dev/null +++ b/bsp/lpc43xx/M4/rtthread_lpc43xx.sct @@ -0,0 +1,23 @@ +; ************************************************************* +; *** Scatter-Loading Description File generated by uVision *** +; ************************************************************* + +LR_IROM1 0x1A000000 0x00080000 { ; load region size_region + ER_IROM1 0x1A000000 0x00080000 { ; load address = execution address + *.o (RESET, +First) + *(InRoot$$Sections) + .ANY (+RO) + } + RW_IRAM1 0x10000000 0x00008000 { ; RW data + .ANY (+RW +ZI) + } + RW_AHBRAM 0x20000000 0x00010000 { ; RW data + * (vbus_ring) + } +} + +LR_IROM2 0x1B000000 0x00080000 { + ER_IROM2 0x1B000000 0x00080000 { ; load address = execution address + * (M0_CODE) + } +} diff --git a/bsp/lpc43xx/M4/template.uvproj b/bsp/lpc43xx/M4/template.uvproj index f93cbd2c11dd33e1d9208327226e9ac2827d3d66..f8bc0558a2b63c4915f8a1df25fe478b5f0c9761 100644 --- a/bsp/lpc43xx/M4/template.uvproj +++ b/bsp/lpc43xx/M4/template.uvproj @@ -211,7 +211,7 @@ 2 1 1 - 1 + 8 1 0 0 @@ -224,10 +224,10 @@ 0 0 0 - 1 + 0 0 0 - 0 + 1 0 0 0 @@ -338,7 +338,7 @@ 1 0 0 - 0 + 1 0 0 0 @@ -371,7 +371,7 @@ - 1 + 0 0 0 0 @@ -379,390 +379,8 @@ 0 0x14000000 0x10000000 - - - - - - - - - - - - LPC43xx RAM - 0x4 - ARM-ADS - - - LPC4357 - NXP (founded by Philips) - IRAM(0x10000000-0x10007FFF) IRAM2(0x20000000-0x2000FFFF) IROM(0x1A000000-0x1A07FFFF) IROM2(0x1B000000-0x1B07FFFF) CLOCK(12000000) CPUTYPE("Cortex-M4") FPU2 - - "STARTUP\NXP\LPC43xx\startup_LPC43xx.s" ("NXP LPC43xx Startup Code") - UL2CM3(-O975 -S0 -C0 -FO7 -FD10000000 -FC800 -FN2 -FF0LPC18xx43xx_512_BA -FS01A000000 -FL080000 -FF1LPC18xx43xx_512_BB -FS11B000000 -FL180000) - 6414 - LPC43xx.H - - - - - - - - - - SFD\NXP\LPC43xx\LPC43xx.SFR - 0 - - - - NXP\LPC43xx\ - NXP\LPC43xx\ - - 0 - 0 - 0 - 0 - 1 - - .\build\ - rtthread_lpc43xx - 1 - 0 - 0 - 1 - 1 - .\build\ - 1 - 0 - 0 - - 0 - 0 - - - 0 - 0 - 0 - 0 - - - 0 - 0 - - - 0 - 0 - - - 0 - 0 - - - 0 - 0 - - 0 - - - - 0 - 0 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 3 - - - - - SARMCM3.DLL - -MPU - DCM.DLL - -pCM4 - SARMCM3.DLL - -MPU - TCM.DLL - -pCM4 - - - - 1 - 0 - 0 - 0 - 16 - - - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - - - 1 - 0 - 0 - 1 - 1 - 0 - 0 - 1 - 0 - - 0 - 1 - - - - - - - - - - - - - .\Dbg_RAM.ini - BIN\UL2CM3.DLL - - - - - 1 - 1 - 0 - 1 - 1 - 4096 - - 1 - BIN\UL2CM3.DLL - "" () - - - - - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - 1 - 1 - 0 - 1 - 1 - 0 - 0 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 1 - 0 - 0 - "Cortex-M4" - - 0 - 0 - 0 - 1 - 1 - 0 - 0 - 2 - 1 - 1 - 8 - 1 - 0 - 0 - 3 - 3 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 1 - 0 - 0 - 0 - 0 - 0 - 1 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x10000000 - 0x8000 - - - 1 - 0x1a000000 - 0x80000 - - - 0 - 0x0 - 0x0 - - - 1 - 0x0 - 0x0 - - - 1 - 0x0 - 0x0 - - - 1 - 0x0 - 0x0 - - - 1 - 0x1a000000 - 0x80000 - - - 1 - 0x1b000000 - 0x80000 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x0 - 0x0 - - - 0 - 0x10000000 - 0x8000 - - - 0 - 0x20000000 - 0x10000 - - - - - - 1 - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - - - - 1 - 0 - 0 - 0 - 0 - 0 - 0 - 0 - - - NO_CRP - - - - - - 1 - 0 - 0 - 0 - 1 - 0 - 0x10000000 - 0x20000000 - + + .\rtthread_lpc43xx.sct @@ -773,5 +391,4 @@ - diff --git a/bsp/lpc43xx/M4/vbus_local_conf.h b/bsp/lpc43xx/M4/vbus_local_conf.h new file mode 100644 index 0000000000000000000000000000000000000000..571c51e6129f9c05ddad57b2819858550ae534da --- /dev/null +++ b/bsp/lpc43xx/M4/vbus_local_conf.h @@ -0,0 +1,8 @@ +#ifndef __VBUS_LOCAL_CONF_H__ +#define __VBUS_LOCAL_CONF_H__ + +#define RT_VBUS_USING_FLOW_CONTROL + +#define RT_VBUS_USING_TESTS + +#endif /* end of include guard: __VBUS_LOCAL_CONF_H__ */ diff --git a/bsp/lpc43xx/applications/application.c b/bsp/lpc43xx/applications/application.c deleted file mode 100644 index e40ad02e48c013b3d0eb8036252594207bfef99b..0000000000000000000000000000000000000000 --- a/bsp/lpc43xx/applications/application.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * File : application.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2014, RT-Thread Development Team - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rt-thread.org/license/LICENSE - * - * Change Logs: - * Date Author Notes - * 2014-07-13 xiaonong port for lpc43xx - */ - -#include -#include -#include -#include "drv_led.h" -#ifdef RT_USING_FINSH -#include -#include -#endif - -/* thread phase init */ -void rt_init_thread_entry(void *parameter) -{ -#ifdef RT_USING_FINSH - /* initialize finsh */ - finsh_system_init(); - finsh_set_device(RT_CONSOLE_DEVICE_NAME); -#endif -} -/*the led thread*/ -ALIGN(RT_ALIGN_SIZE) -static rt_uint8_t led_stack[ 512 ]; -static struct rt_thread led_thread; -static void led_thread_entry(void *parameter) -{ - rt_uint8_t led_value = 0; - rt_device_t led_dev; - rt_led_hw_init(); - led_dev = rt_device_find("led"); - if (led_dev == RT_NULL) - { - rt_kprintf("can not find the led device!\n"); - return; - } - while (1) - { - /* led0 on */ - led_value = 1; - led_dev->write(led_dev, 0, &led_value, 1); - rt_thread_delay(RT_TICK_PER_SECOND / 2); /* sleep 0.5 second and switch to other thread */ - - /* led0 off */ - led_value = 0; - led_dev->write(led_dev, 0, &led_value, 1); - rt_thread_delay(RT_TICK_PER_SECOND / 2); - } -} - -int rt_application_init(void) -{ - rt_thread_t tid; - rt_err_t result; - tid = rt_thread_create("init", - rt_init_thread_entry, RT_NULL, - 2048, RT_THREAD_PRIORITY_MAX / 3, 20); - if (tid != RT_NULL) rt_thread_startup(tid); - /* init led thread */ - result = rt_thread_init(&led_thread, - "led", - led_thread_entry, - RT_NULL, - (rt_uint8_t *)&led_stack[0], - sizeof(led_stack), - 20, - 5); - if (result == RT_EOK) - { - rt_thread_startup(&led_thread); - } - return 0; -} diff --git a/bsp/lpc43xx/bin2C.py b/bsp/lpc43xx/bin2C.py new file mode 100644 index 0000000000000000000000000000000000000000..ea7bf2959d93824c095ef0b6e22e0f1511e6b6ba --- /dev/null +++ b/bsp/lpc43xx/bin2C.py @@ -0,0 +1,14 @@ +#!/bin/env python + +import sys + +fi = open(sys.argv[1], 'rb') +fo = open(sys.argv[2], 'wb') + +idx = 0 +for i in fi.read(): + idx += 1 + fo.write('0x%02x, ' % ord(i)) + if idx % 16 == 0: + fo.write('\n') +fo.write('\n') diff --git a/bsp/lpc43xx/drivers/drv_uart.c b/bsp/lpc43xx/drivers/drv_uart.c index 9c1f0ada8c97bf0dc4db0fa9416e28af4e63537c..70f4a880e1a837e2d1f77a1890d367d7fff72cad 100644 --- a/bsp/lpc43xx/drivers/drv_uart.c +++ b/bsp/lpc43xx/drivers/drv_uart.c @@ -26,19 +26,7 @@ struct lpc_uart static rt_err_t lpc_configure(struct rt_serial_device *serial, struct serial_configure *cfg) { -// struct lpc_uart *uart; - - RT_ASSERT(serial != RT_NULL); - // uart = (struct lpc_uart *)serial->parent.user_data; - - - - // Initialize FIFO for UART0 peripheral -// UART_FIFOConfig(uart->USART, &UARTFIFOConfigStruct); - -// UART_TxCmd(uart->USART, ENABLE); - return RT_EOK; } @@ -95,60 +83,62 @@ static const struct rt_uart_ops lpc_uart_ops = lpc_getc, }; -#if defined(RT_USING_UART0) -/* UART0 device driver structure */ -struct lpc_uart uart0 = -{ - LPC_USART0, - USART0_IRQn, -}; -struct rt_serial_device serial0; - -void UART0_IRQHandler(void) +static void _do_uart_isr(struct rt_serial_device *sdev) { struct lpc_uart *uart; - volatile uint32_t intsrc, temp; + uint32_t intsrc; - uart = &uart0; - - /* enter interrupt */ - rt_interrupt_enter(); + uart = sdev->parent.user_data; /* Determine the interrupt source */ intsrc = uart->USART->IIR & UART_IIR_INTID_MASK; switch (intsrc) { - - case UART_IIR_INTID_RLS: /* Receive Line Status interrupt*/ + case UART_IIR_INTID_RLS: + /* Receive Line Status interrupt */ /* read the line status */ intsrc = uart->USART->LSR; /* Receive an error data */ if (intsrc & UART_LSR_PE) { - temp = LPC_USART0->RBR; + uart->USART->RBR; } break; - - case UART_IIR_INTID_RDA: /* Receive data */ - case UART_IIR_INTID_CTI: /* Receive data timeout */ + case UART_IIR_INTID_RDA: + /* Receive data */ + case UART_IIR_INTID_CTI: + /* Receive data timeout */ /* read the data to buffer */ while (uart->USART->LSR & UART_LSR_RDR) { - rt_hw_serial_isr(&serial0, RT_SERIAL_EVENT_RX_IND); + rt_hw_serial_isr(sdev, RT_SERIAL_EVENT_RX_IND); } break; default: break; } +} - /* leave interrupt */ +#if defined(RT_USING_UART0) +/* UART0 device driver structure */ +struct lpc_uart uart0 = +{ + LPC_USART0, + USART0_IRQn, +}; +struct rt_serial_device serial0; + +void UART0_IRQHandler(void) +{ + rt_interrupt_enter(); + _do_uart_isr(&serial0); rt_interrupt_leave(); } #endif + #if defined(RT_USING_UART2) -/* UART2 device driver structure */ struct lpc_uart uart2 = { LPC_USART2, @@ -158,47 +148,28 @@ struct rt_serial_device serial2; void UART2_IRQHandler(void) { - struct lpc_uart *uart; - uint32_t intsrc, temp; - - uart = &uart2; - - /* enter interrupt */ rt_interrupt_enter(); + _do_uart_isr(&serial2); + rt_interrupt_leave(); +} +#endif - /* Determine the interrupt source */ - intsrc = uart->USART->IIR & UART_IIR_INTID_MASK; - - switch (intsrc) - { - - case UART_IIR_INTID_RLS: /* Receive Line Status interrupt*/ - /* read the line status */ - intsrc = uart->USART->LSR; - /* Receive an error data */ - if (intsrc & UART_LSR_PE) - { - temp = LPC_USART0->RBR; - } - break; - - case UART_IIR_INTID_RDA: /* Receive data */ - case UART_IIR_INTID_CTI: /* Receive data timeout */ - /* read the data to buffer */ - while (uart->USART->LSR & UART_LSR_RDR) - { - rt_hw_serial_isr(&serial0, RT_SERIAL_EVENT_RX_IND); - } - break; - - default: - break; - } +#if defined(RT_USING_UART3) +struct lpc_uart uart3 = +{ + LPC_USART3, + USART3_IRQn, +}; +struct rt_serial_device serial3; - /* leave interrupt */ +void UART3_IRQHandler(void) +{ + rt_interrupt_enter(); + _do_uart_isr(&serial3); rt_interrupt_leave(); } #endif + void rt_hw_uart_init(void) { struct lpc_uart *uart; @@ -212,7 +183,7 @@ void rt_hw_uart_init(void) config.parity = PARITY_NONE; config.stop_bits = STOP_BITS_1; config.invert = NRZ_NORMAL; - config.bufsz = RT_SERIAL_RB_BUFSZ; + config.bufsz = RT_SERIAL_RB_BUFSZ; serial0.ops = &lpc_uart_ops; serial0.config = config; @@ -221,36 +192,36 @@ void rt_hw_uart_init(void) LPC_CCU1->CLK_M4_GPIO_CFG |= 0x01; while (!(LPC_CCU1->CLK_M4_GPIO_STAT & 0x01)); - /* Enable USART1 peripheral clock */ + /* Enable USART0 peripheral clock */ LPC_CCU2->CLK_APB0_USART0_CFG |= 0x01; while (!(LPC_CCU2->CLK_APB0_USART0_STAT & 0x01)); - /* Enable USART1 register interface clock */ + /* Enable USART0 register interface clock */ LPC_CCU1->CLK_M4_USART0_CFG |= 0x01; while (!(LPC_CCU1->CLK_M4_USART0_STAT & 0x01)); /* Init GPIO pins */ LPC_SCU->SFSP2_0 = (1 << 6) | /* Input buffer enabled */ - (1 << 4) | /* Pull-up disabled */ - (1 << 0) ; /* Pin P2_0 used as U0_TXD */ + (1 << 4) | /* Pull-up disabled */ + (1 << 0) ; /* Pin P2_0 used as U0_TXD */ LPC_SCU->SFSP2_1 = (1 << 6) | /* Input buffer enabled */ - (1 << 4) | /* Pull-up disabled */ - (1 << 0) ; /* Pin P2_1 used as U0_RXD */ + (1 << 4) | /* Pull-up disabled */ + (1 << 0) ; /* Pin P2_1 used as U0_RXD */ /* Init USART0 */ - LPC_USART0->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ - LPC_USART0->DLL = 0x06; /* 115200 Baudrate @ 12 MHz IRC */ - LPC_USART0->DLM = 0x00; - LPC_USART0->FDR = 0xC1; - LPC_USART0->LCR = 0x03; /* DLAB = 0 */ + uart->USART->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ + uart->USART->DLL = 0x06; /* 115200 Baudrate @ 12 MHz IRC */ + uart->USART->DLM = 0x00; + uart->USART->FDR = 0xC1; + uart->USART->LCR = 0x03; /* DLAB = 0 */ /* preemption = 1, sub-priority = 1 */ NVIC_SetPriority(uart->USART_IRQn, ((0x01 << 3) | 0x01)); /* Enable Interrupt for UART channel */ NVIC_EnableIRQ(uart->USART_IRQn); - /* register UART1 device */ + /* register UART0 device */ rt_hw_serial_register(&serial0, "uart0", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); @@ -263,7 +234,7 @@ void rt_hw_uart_init(void) config.parity = PARITY_NONE; config.stop_bits = STOP_BITS_1; config.invert = NRZ_NORMAL; - config.bufsz = RT_SERIAL_RB_BUFSZ; + config.bufsz = RT_SERIAL_RB_BUFSZ; serial2.ops = &lpc_uart_ops; serial2.config = config; @@ -272,39 +243,91 @@ void rt_hw_uart_init(void) LPC_CCU1->CLK_M4_GPIO_CFG |= 0x01; while (!(LPC_CCU1->CLK_M4_GPIO_STAT & 0x01)); - /* Enable USART1 peripheral clock */ - LPC_CCU2->CLK_APB0_USART0_CFG |= 0x01; + /* Enable USART2 peripheral clock */ + LPC_CCU2->CLK_APB2_USART2_CFG |= 0x01; while (!(LPC_CCU2->CLK_APB2_USART2_STAT & 0x01)); /* Enable USART2 register interface clock */ - LPC_CCU1->CLK_M4_USART0_CFG |= 0x01; + LPC_CCU1->CLK_M4_USART2_CFG |= 0x01; while (!(LPC_CCU1->CLK_M4_USART2_STAT & 0x01)); /* Init GPIO pins */ LPC_SCU->SFSP1_15 = (1 << 6) | /* Input buffer enabled */ - (1 << 4) | /* Pull-up disabled */ - (1 << 0) ; /* Pin P1_15 used as U2_TXD */ + (1 << 4) | /* Pull-up disabled */ + (1 << 0) ; /* Pin P1_15 used as U2_TXD */ LPC_SCU->SFSP1_16 = (1 << 6) | /* Input buffer enabled */ - (1 << 4) | /* Pull-up disabled */ - (1 << 0) ; /* Pin P1_16 used as U2_RXD */ + (1 << 4) | /* Pull-up disabled */ + (1 << 0) ; /* Pin P1_16 used as U2_RXD */ /* Init USART2 */ - LPC_USART2->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ - LPC_USART2->DLL = 0x06; /* 115200 Baudrate @ 12 MHz IRC */ - LPC_USART2->DLM = 0x00; - LPC_USART2->FDR = 0xC1; - LPC_USART2->LCR = 0x03; /* DLAB = 0 */ - + uart->USART->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ + uart->USART->DLL = 0x06; /* 115200 Baudrate @ 12 MHz IRC */ + uart->USART->DLM = 0x00; + uart->USART->FDR = 0xC1; + uart->USART->LCR = 0x03; /* DLAB = 0 */ + /* preemption = 1, sub-priority = 1 */ NVIC_SetPriority(uart->USART_IRQn, ((0x01 << 3) | 0x01)); /* Enable Interrupt for UART channel */ NVIC_EnableIRQ(uart->USART_IRQn); - /* register UART1 device */ + /* register UART2 device */ rt_hw_serial_register(&serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, uart); #endif +#ifdef RT_USING_UART3 + uart = &uart3; + config.baud_rate = BAUD_RATE_115200; + config.bit_order = BIT_ORDER_LSB; + config.data_bits = DATA_BITS_8; + config.parity = PARITY_NONE; + config.stop_bits = STOP_BITS_1; + config.invert = NRZ_NORMAL; + config.bufsz = RT_SERIAL_RB_BUFSZ; + + serial3.ops = &lpc_uart_ops; + serial3.config = config; + + /* Enable GPIO register interface clock */ + LPC_CCU1->CLK_M4_GPIO_CFG |= 0x01; + while (!(LPC_CCU1->CLK_M4_GPIO_STAT & 0x01)); + + /* Enable USART3 peripheral clock */ + LPC_CCU2->CLK_APB2_USART3_CFG |= 0x01; + while (!(LPC_CCU2->CLK_APB2_USART3_STAT & 0x01)); + + /* Enable USART3 register interface clock */ + LPC_CCU1->CLK_M4_USART3_CFG |= 0x01; + while (!(LPC_CCU1->CLK_M4_USART3_STAT & 0x01)); + + /* Init GPIO pins */ + LPC_SCU->SFSP2_3 = (1 << 6) | /* Input buffer enabled */ + (1 << 4) | /* Pull-up disabled */ + (2 << 0) ; /* Pin P1_15 used as U2_TXD */ + + LPC_SCU->SFSP2_4 = (1 << 6) | /* Input buffer enabled */ + (1 << 4) | /* Pull-up disabled */ + (2 << 0) ; /* Pin P1_16 used as U2_RXD */ + + /* Init USART3 */ + uart->USART->LCR = 0x83; /* 8 bits, no Parity, 1 Stop bit */ + uart->USART->DLL = 0x06; /* 115200 Baudrate @ 12 MHz IRC */ + uart->USART->DLM = 0x00; + uart->USART->FDR = 0xC1; + uart->USART->LCR = 0x03; /* DLAB = 0 */ + + /* preemption = 1, sub-priority = 1 */ + NVIC_SetPriority(uart->USART_IRQn, ((0x01 << 3) | 0x01)); + + /* Enable Interrupt for UART channel */ + NVIC_EnableIRQ(uart->USART_IRQn); + + /* register UART2 device */ + rt_hw_serial_register(&serial3, "uart3", + RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, + uart); +#endif } diff --git a/bsp/lpc43xx/readme.txt b/bsp/lpc43xx/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..022659903256a8d11cc32fb7d8dba929af1b84e7 --- /dev/null +++ b/bsp/lpc43xx/readme.txt @@ -0,0 +1,4 @@ +1. M4 run on flash bank A. M0 run on flash bank B and the binary code of M0 is + embedded into the code of M4. +3. Compile the project in M0/ first and then compile the project in M4/. Then + flash it into the chip with JLink. diff --git a/components/vbus/SConscript b/components/vbus/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..e9097d19ffd422df89b68323576328c3a69b737c --- /dev/null +++ b/components/vbus/SConscript @@ -0,0 +1,29 @@ +# RT-Thread building script for component + +import SCons, os +from building import * + +group = [] +if not GetDepend(['RT_USING_VBUS']): + Return('group') + +cwd = GetCurrentDir() +src = Glob('*.c') + +for c, f in [['RT_USING_VBUS_RFS', 'utilities/rfs.c'], + ['RT_USING_VBUS_RSHELL', 'utilities/rshell.c'], + ]: + if GetDepend(c): + src += Glob(f) + +with open(os.path.join(Dir('#').get_abspath(), 'vbus_local_conf.h'), 'r') as f: + cpp = SCons.cpp.PreProcessor() + cpp.process_contents(f.read()) + if 'RT_VBUS_USING_TESTS' in cpp.cpp_namespace: + src += Glob('tests/*.c') + +CPPPATH = [cwd, os.path.join(cwd, 'share_hdr')] + +group = DefineGroup('VBus', src, depend = ['RT_USING_VBUS'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/vbus/prio_queue.c b/components/vbus/prio_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..b402e0376a5a70c99cc2e68f9f77e6a1310b4c38 --- /dev/null +++ b/components/vbus/prio_queue.c @@ -0,0 +1,276 @@ +/* + * Priority Queue + * + * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-11-04 Grissiom add comment + */ + +#include +#include + +#include "prio_queue.h" + +struct rt_prio_queue_item { + struct rt_prio_queue_item *next; + /* data follows */ +}; + +static void _do_push(struct rt_prio_queue *que, + rt_uint8_t prio, + struct rt_prio_queue_item *item) +{ + if (que->head[prio] == RT_NULL) + { + que->head[prio] = item; + que->bitmap |= 1 << prio; + } + else + { + RT_ASSERT(que->tail[prio]); + que->tail[prio]->next = item; + } + que->tail[prio] = item; +} + +static struct rt_prio_queue_item* _do_pop(struct rt_prio_queue *que) +{ + int ffs; + struct rt_prio_queue_item *item; + + ffs = __rt_ffs(que->bitmap); + if (ffs == 0) + return RT_NULL; + ffs--; + + item = que->head[ffs]; + RT_ASSERT(item); + + que->head[ffs] = item->next; + if (que->head[ffs] == RT_NULL) + { + que->bitmap &= ~(1 << ffs); + } + + return item; +} + +rt_err_t rt_prio_queue_init(struct rt_prio_queue *que, + const char *name, + void *buf, + rt_size_t bufsz, + rt_size_t itemsz) +{ + RT_ASSERT(que); + + rt_memset(que, 0, sizeof(*que)); + + rt_list_init(&(que->suspended_pop_list)); + + rt_mp_init(&que->pool, name, buf, bufsz, + sizeof(struct rt_prio_queue_item) + itemsz); + + que->item_sz = itemsz; + + return RT_EOK; +} + +void rt_prio_queue_detach(struct rt_prio_queue *que) +{ + /* wake up all suspended pop threads, push thread is suspended on mempool. + */ + while (!rt_list_isempty(&(que->suspended_pop_list))) + { + rt_thread_t thread; + + /* disable interrupt */ + rt_ubase_t temp = rt_hw_interrupt_disable(); + + /* get next suspend thread */ + thread = rt_list_entry(que->suspended_pop_list.next, struct rt_thread, tlist); + /* set error code to RT_ERROR */ + thread->error = -RT_ERROR; + + rt_thread_resume(thread); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + rt_mp_detach(&que->pool); +} + +#ifdef RT_USING_HEAP +struct rt_prio_queue* rt_prio_queue_create(const char *name, + rt_size_t item_nr, + rt_size_t item_sz) +{ + struct rt_prio_queue *que; + rt_size_t bufsz; + + bufsz = item_nr * (sizeof(struct rt_prio_queue_item) + + item_sz + + sizeof(void*)); + + RT_ASSERT(item_nr); + + que = rt_malloc(sizeof(*que) + bufsz); + if (!que) + return RT_NULL; + + rt_prio_queue_init(que, name, que+1, bufsz, item_sz); + + return que; +} + +void rt_prio_queue_delete(struct rt_prio_queue *que) +{ + rt_prio_queue_detach(que); + rt_free(que); +} +#endif + +rt_err_t rt_prio_queue_push(struct rt_prio_queue *que, + rt_uint8_t prio, + void *data, + rt_int32_t timeout) +{ + rt_ubase_t level; + struct rt_prio_queue_item *item; + + RT_ASSERT(que); + + if (prio >= RT_PRIO_QUEUE_PRIO_MAX) + return -RT_ERROR; + + item = rt_mp_alloc(&que->pool, timeout); + if (item == RT_NULL) + return -RT_ENOMEM; + + rt_memcpy(item+1, data, que->item_sz); + item->next = RT_NULL; + + level = rt_hw_interrupt_disable(); + + _do_push(que, prio, item); + + if (!rt_list_isempty(&(que->suspended_pop_list))) + { + rt_thread_t thread; + + /* get thread entry */ + thread = rt_list_entry(que->suspended_pop_list.next, + struct rt_thread, + tlist); + /* resume it */ + rt_thread_resume(thread); + rt_hw_interrupt_enable(level); + + /* perform a schedule */ + rt_schedule(); + + return RT_EOK; + } + + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que, + void *data, + rt_int32_t timeout) +{ + rt_ubase_t level; + struct rt_prio_queue_item *item; + + RT_ASSERT(que); + RT_ASSERT(data); + + level = rt_hw_interrupt_disable(); + for (item = _do_pop(que); + item == RT_NULL; + item = _do_pop(que)) + { + rt_thread_t thread; + + if (timeout == 0) + { + rt_hw_interrupt_enable(level); + return -RT_ETIMEOUT; + } + + RT_DEBUG_NOT_IN_INTERRUPT; + + thread = rt_thread_self(); + thread->error = RT_EOK; + rt_thread_suspend(thread); + + rt_list_insert_before(&(que->suspended_pop_list), &(thread->tlist)); + + if (timeout > 0) + { + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + rt_hw_interrupt_enable(level); + + rt_schedule(); + + /* thread is waked up */ + if (thread->error != RT_EOK) + return thread->error; + level = rt_hw_interrupt_disable(); + } + + rt_hw_interrupt_enable(level); + + rt_memcpy(data, item+1, que->item_sz); + rt_mp_free(item); + + return RT_EOK; +} + +void rt_prio_queue_dump(struct rt_prio_queue *que) +{ + int level = 0; + + rt_kprintf("bitmap: %08x\n", que->bitmap); + for (level = 0; level < RT_PRIO_QUEUE_PRIO_MAX; level++) + { + struct rt_prio_queue_item *item; + + rt_kprintf("%2d: ", level); + for (item = que->head[level]; + item; + item = item->next) + { + rt_kprintf("%p, ", item); + } + rt_kprintf("\n"); + } +} + diff --git a/components/vbus/prio_queue.h b/components/vbus/prio_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..8a29cbb715013991d40f62a8c2dbf4b9b6038085 --- /dev/null +++ b/components/vbus/prio_queue.h @@ -0,0 +1,73 @@ +/* + * Priority Queue + * + * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-11-04 Grissiom add comment + */ + +#ifndef __PRIO_QUEUE_H__ +#define __PRIO_QUEUE_H__ + +#include + +#define RT_PRIO_QUEUE_PRIO_MAX 32 + +struct rt_prio_queue_item; + +struct rt_prio_queue { + rt_uint32_t bitmap; + struct rt_prio_queue_item *head[RT_PRIO_QUEUE_PRIO_MAX]; + struct rt_prio_queue_item *tail[RT_PRIO_QUEUE_PRIO_MAX]; + /* push thread suspend on the mempool, not queue */ + rt_list_t suspended_pop_list; + rt_size_t item_sz; + + struct rt_mempool pool; +}; + +rt_err_t rt_prio_queue_init(struct rt_prio_queue *que, + const char *name, + void *buf, + rt_size_t bufsz, + rt_size_t itemsz); +void rt_prio_queue_detach(struct rt_prio_queue *que); + +rt_err_t rt_prio_queue_push(struct rt_prio_queue *que, + rt_uint8_t prio, + void *data, + rt_int32_t timeout); +rt_err_t rt_prio_queue_pop(struct rt_prio_queue *que, + void *data, + rt_int32_t timeout); +#ifdef RT_USING_HEAP +struct rt_prio_queue* rt_prio_queue_create(const char *name, + rt_size_t item_nr, + rt_size_t item_sz); +void rt_prio_queue_delete(struct rt_prio_queue *que); +#endif + +void rt_prio_queue_dump(struct rt_prio_queue *que); + +#endif /* end of include guard: __PRIO_QUEUE_H__ */ diff --git a/components/vbus/rt_watermark_queue.c b/components/vbus/rt_watermark_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..329e9f331c1f8cb751d094030e6c3e5672b61711 --- /dev/null +++ b/components/vbus/rt_watermark_queue.c @@ -0,0 +1,71 @@ +/* + * Water Gauge + * + * COPYRIGHT (C) 2014-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-04-16 Grissiom first version + */ + +#include +#include + +#include "rt_watermark_queue.h" + +void rt_wm_que_set_mark(struct rt_watermark_queue *wg, + unsigned int low, unsigned int high) +{ + RT_ASSERT(low <= high); + + wg->high_mark = high; + wg->low_mark = low; +} + +void rt_wm_que_init(struct rt_watermark_queue *wg, + unsigned int low, unsigned int high) +{ + rt_wm_que_set_mark(wg, low, high); + rt_list_init(&wg->suspended_threads); + wg->level = 0; +} + +void rt_wm_que_dump(struct rt_watermark_queue *wg) +{ + struct rt_list_node *node; + + rt_kprintf("wg %p: low: %d, high: %d, cur: %d\n", + wg, wg->low_mark, wg->high_mark, wg->level); + rt_kprintf("thread suspend:"); + for (node = wg->suspended_threads.next; + node != &wg->suspended_threads; + node = node->next) + { + rt_thread_t thread; + + thread = rt_list_entry(wg->suspended_threads.next, + struct rt_thread, + tlist); + rt_kprintf(" %.*s", RT_NAME_MAX, thread->name); + } + rt_kprintf("\n"); +} diff --git a/components/vbus/rt_watermark_queue.h b/components/vbus/rt_watermark_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..1fd51e07c259bc8f2e8f0a4d82ce63e1ad9fb0f0 --- /dev/null +++ b/components/vbus/rt_watermark_queue.h @@ -0,0 +1,149 @@ +/* + * Thread queue with water mark + * + * COPYRIGHT (C) 2014-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-04-16 Grissiom first version + */ + +struct rt_watermark_queue +{ + /* Current water level. */ + unsigned int level; + unsigned int high_mark; + unsigned int low_mark; + rt_list_t suspended_threads; +}; + +/** Init the struct rt_watermark_queue. + */ +void rt_wm_que_init(struct rt_watermark_queue *wg, + unsigned int low, unsigned int high); +void rt_wm_que_set_mark(struct rt_watermark_queue *wg, + unsigned int low, unsigned int high); +void rt_wm_que_dump(struct rt_watermark_queue *wg); + +/* Water marks are often used in performance critical places. Benchmark shows + * inlining functions will have 10% performance gain in some situation(for + * example, VBus). So keep the inc/dec compact and inline. */ + +/** Increase the water level. + * + * It should be called in the thread that want to raise the water level. If the + * current level is above the high mark, the thread will be suspended up to + * @timeout ticks. + * + * @return RT_EOK if water level increased successfully. -RT_EFULL on @timeout + * is zero and the level is above water mark. -RT_ETIMEOUT if timeout occurred. + */ +rt_inline rt_err_t rt_wm_que_inc(struct rt_watermark_queue *wg, + int timeout) +{ + rt_base_t ilvl; + + /* Assert as early as possible. */ + if (timeout != 0) + { + RT_DEBUG_IN_THREAD_CONTEXT; + } + + ilvl = rt_hw_interrupt_disable(); + + while (wg->level > wg->high_mark) + { + rt_thread_t thread; + + if (timeout == 0) + { + rt_hw_interrupt_enable(ilvl); + return -RT_EFULL; + } + + thread = rt_thread_self(); + thread->error = RT_EOK; + rt_thread_suspend(thread); + rt_list_insert_after(&wg->suspended_threads, &thread->tlist); + if (timeout > 0) + { + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + rt_hw_interrupt_enable(ilvl); + rt_schedule(); + if (thread->error != RT_EOK) + return thread->error; + + ilvl = rt_hw_interrupt_disable(); + } + + wg->level++; + + if (wg->level == 0) + { + wg->level = ~0; + } + + rt_hw_interrupt_enable(ilvl); + + return RT_EOK; +} + +/** Decrease the water level. + * + * It should be called by the consumer that drain the water out. If the water + * level reached low mark, all the thread suspended in this queue will be waken + * up. It's safe to call this function in interrupt context. + */ +rt_inline void rt_wm_que_dec(struct rt_watermark_queue *wg) +{ + int need_sched = 0; + rt_base_t ilvl; + + if (wg->level == 0) + return; + + ilvl = rt_hw_interrupt_disable(); + wg->level--; + if (wg->level == wg->low_mark) + { + /* There should be spaces between the low mark and high mark, so it's + * safe to resume all the threads. */ + while (!rt_list_isempty(&wg->suspended_threads)) + { + rt_thread_t thread; + + thread = rt_list_entry(wg->suspended_threads.next, + struct rt_thread, + tlist); + rt_thread_resume(thread); + need_sched = 1; + } + } + rt_hw_interrupt_enable(ilvl); + + if (need_sched) + rt_schedule(); +} diff --git a/components/vbus/share_hdr/vbus_api.h b/components/vbus/share_hdr/vbus_api.h new file mode 100644 index 0000000000000000000000000000000000000000..fb15fa24b0c0f920a60283ba23feb9a7c8d93008 --- /dev/null +++ b/components/vbus/share_hdr/vbus_api.h @@ -0,0 +1,79 @@ +#ifndef __VBUS_API_H__ +#define __VBUS_API_H__ + +#include "vbus_conf.h" + +#define RT_VBUS_CHANNEL_NR 32 + +#define RT_VBUS_BLK_HEAD_SZ 4 +#define RT_VBUS_MAX_PKT_SZ (256 - RT_VBUS_BLK_HEAD_SZ) + +#ifndef __ASSEMBLY__ +#include /* For size_t */ + +struct rt_vbus_blk +{ + unsigned char id; + unsigned char qos; + unsigned char len; + unsigned char reserved; + unsigned char data[60]; +} __attribute__((packed)); + +struct rt_vbus_ring +{ + volatile size_t put_idx; + volatile size_t get_idx; + /* whether the writer is blocked on this ring. For RTT, it means the + * central writer thread is waiting. For Linux, it means there are some + * threads waiting for space to write. + * + * Note that we don't record whether there are reading thread blocked. When + * there is new data, the other side will always be waked up. */ + volatile unsigned int blocked; + struct rt_vbus_blk blks[RT_VMM_RB_BLK_NR]; +}; + +enum +{ + RT_VBUS_CHN0_CMD_ENABLE, + RT_VBUS_CHN0_CMD_DISABLE, + RT_VBUS_CHN0_CMD_SET, + RT_VBUS_CHN0_CMD_ACK, + RT_VBUS_CHN0_CMD_NAK, + /* If the recieving side reached high water mark. It has the right to + * suspend the channel. All the server/client should know about this + * command but the one that does not implement flow control could ignore + * this command. */ + RT_VBUS_CHN0_CMD_SUSPEND, + RT_VBUS_CHN0_CMD_RESUME, + RT_VBUS_CHN0_CMD_MAX, +}; + +enum rt_vbus_chn_status +{ + /* initial state, available for reuse */ + RT_VBUS_CHN_ST_AVAILABLE, + /* ACK DISABLE send(CS) or received(CS), but not ready for reuse.(the + * channel is not closed by this end) */ + RT_VBUS_CHN_ST_CLOSED, + /* ENABLE send(client) or received(server) */ + RT_VBUS_CHN_ST_ESTABLISHING, + /* ACK SET send(C) or received(S) */ + RT_VBUS_CHN_ST_ESTABLISHED, + /* Channel suspended by flow control. */ + RT_VBUS_CHN_ST_SUSPEND, + /* DISABLE received(CS) */ + RT_VBUS_CHN_ST_CLOSING, +}; +#endif + +#undef BUILD_ASSERT +/* borrowed from http://lxr.linux.no/linux+v2.6.26.5/include/linux/kernel.h#L494 */ +#define BUILD_ASSERT(condition) ((void)sizeof(char[1 - 2*!(condition)])) + +/* max length of a channel name, including the \0 */ +#define RT_VBUS_CHN_NAME_MAX 16 + +#endif /* end of include guard: __VBUS_API_H__ */ + diff --git a/components/vbus/vbus.c b/components/vbus/vbus.c new file mode 100644 index 0000000000000000000000000000000000000000..7005e5251393bb1c4c93d6a9c7da7a7252a71bf3 --- /dev/null +++ b/components/vbus/vbus.c @@ -0,0 +1,1371 @@ +/* + * VMM Bus + * + * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-11-04 Grissiom add comment + */ + +#include +#include +#include + +#include "vbus.h" +#include "prio_queue.h" +#include "vbus_hw.h" + +//#define RT_VBUS_STATISTICS + +#define RT_VBUS_RB_LOW_TICK (RT_VMM_RB_BLK_NR * 2 / 3) +#define RT_VBUS_RB_TICK_STEP (100) + +#ifndef RT_USING_LOGTRACE +/* console could be run on vbus. If we log on it, there will be oops. */ +#define vbus_debug(...) +#define vbus_verbose(...) +#define vbus_info(...) +#define vbus_error(...) +#else // have RT_USING_LOGTRACE +#include + +#if defined(log_session_lvl) +/* Define log_trace_session as const so the compiler could optimize some log + * out. */ +const static struct log_trace_session _lgs = { + .id = {.name = "vbus"}, + .lvl = LOG_TRACE_LEVEL_VERBOSE, +}; + +#define vbus_debug(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_DEBUG, fmt, ##__VA_ARGS__) +#define vbus_verbose(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_VERBOSE, fmt, ##__VA_ARGS__) +#define vbus_info(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_INFO, fmt, ##__VA_ARGS__) +#define vbus_error(fmt, ...) log_session_lvl(&_lgs, LOG_TRACE_LEVEL_ERROR, fmt, ##__VA_ARGS__) +#else +static struct log_trace_session _lgs = { + .id = {.name = "vbus"}, + .lvl = LOG_TRACE_LEVEL_VERBOSE, +}; +#define vbus_debug(fmt, ...) log_session(&_lgs, LOG_TRACE_DEBUG""fmt, ##__VA_ARGS__) +#define vbus_verbose(fmt, ...) log_session(&_lgs, LOG_TRACE_VERBOSE""fmt, ##__VA_ARGS__) +#define vbus_info(fmt, ...) log_session(&_lgs, LOG_TRACE_INFO""fmt, ##__VA_ARGS__) +#define vbus_error(fmt, ...) log_session(&_lgs, LOG_TRACE_ERROR""fmt, ##__VA_ARGS__) +#endif +#endif // RT_USING_LOGTRACE + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0])) +#endif + +struct rt_vbus_ring *RT_VBUS_OUT_RING; +struct rt_vbus_ring *RT_VBUS_IN_RING; + +const char *rt_vbus_chn_st2str[] = { + "available", + "closed", + "establishing", + "established", + "suspended", + "closing", +}; + +const char *rt_vbus_sess_st2str[] = { + "available", + "listening", + "establishing", +}; + +const char *rt_vbus_cmd2str[] = { + "ENABLE", + "DISABLE", + "SET", + "ACK", + "NAK", + "SUSPEND", + "RESUME", +}; + +static char* dump_cmd_pkt(unsigned char *dp, size_t dsize); + +/* 4 bytes for the head */ +#define LEN2BNR(len) ((len + RT_VBUS_BLK_HEAD_SZ \ + + sizeof(struct rt_vbus_blk) - 1) \ + / sizeof(struct rt_vbus_blk)) + +rt_inline void _ring_add_get_bnr(struct rt_vbus_ring *ring, + rt_size_t bnr) +{ + int nidx = ring->get_idx + bnr; + + if (nidx >= RT_VMM_RB_BLK_NR) + { + nidx -= RT_VMM_RB_BLK_NR; + } + rt_vbus_smp_wmb(); + ring->get_idx = nidx; +} + +rt_inline int _bus_ring_space_nr(struct rt_vbus_ring *rg) +{ + int delta; + + rt_vbus_smp_rmb(); + delta = rg->get_idx - rg->put_idx; + + if (delta > 0) + { + /* Put is behind the get. */ + return delta - 1; + } + else + { + /* delta is negative. */ + return RT_VMM_RB_BLK_NR + delta - 1; + } +} + +struct rt_vbus_pkg { + rt_uint8_t id; + rt_uint8_t prio; + rt_uint8_t finished; + rt_uint8_t len; + const void *data; +}; + +/* chn0 is always connected */ +static enum rt_vbus_chn_status _chn_status[RT_VBUS_CHANNEL_NR]; + +rt_inline int _chn_connected(unsigned char chnr) +{ + return _chn_status[chnr] == RT_VBUS_CHN_ST_ESTABLISHED || + _chn_status[chnr] == RT_VBUS_CHN_ST_SUSPEND; +} + +#ifdef RT_VBUS_USING_FLOW_CONTROL +#include +struct rt_watermark_queue _chn_wm_que[RT_VBUS_CHANNEL_NR]; +void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high) +{ + RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_wm_que))); + rt_wm_que_set_mark(&_chn_wm_que[chnr], low, high); +} + +/* Threads suspended by the flow control of other side. */ +rt_list_t _chn_suspended_threads[RT_VBUS_CHANNEL_NR]; + +struct +{ + unsigned int level; + unsigned int high_mark; + unsigned int low_mark; + /* The suspend command does not have ACK. So if the other side still + * sending pkg after SUSPEND, warn it again. Also use it as a flag that + * tell me whether are we dropping from the high mark or not when reaching + * the low mark. */ + unsigned int last_warn; +} _chn_recv_wm[RT_VBUS_CHANNEL_NR]; + +void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high) +{ + RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_recv_wm))); + _chn_recv_wm[chnr].low_mark = low; + _chn_recv_wm[chnr].high_mark = high; +} +#else +void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high) +{} +void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high) +{} +#endif + +struct { + rt_vbus_event_listener indicate; + void *ctx; +} _vbus_rx_indi[RT_VBUS_EVENT_ID_MAX][RT_VBUS_CHANNEL_NR]; + +void rt_vbus_register_listener(unsigned char chnr, + enum rt_vbus_event_id eve, + rt_vbus_event_listener indi, + void *ctx) +{ + RT_ASSERT(chnr != 0 && chnr < RT_VBUS_CHANNEL_NR); + RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0])); + + _vbus_rx_indi[eve][chnr].indicate = indi; + _vbus_rx_indi[eve][chnr].ctx = ctx; +} + +static void _vbus_indicate(enum rt_vbus_event_id eve, unsigned char chnr) +{ + RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0])); + + if (_vbus_rx_indi[eve][chnr].indicate) + _vbus_rx_indi[eve][chnr].indicate(_vbus_rx_indi[eve][chnr].ctx); +} + +#define _BUS_OUT_THRD_STACK_SZ 2048 +#define _BUS_OUT_THRD_PRIO 8 +#define _BUS_OUT_PKG_NR RT_VMM_RB_BLK_NR + +static struct rt_thread _bus_out_thread; +static rt_uint8_t _bus_out_thread_stack[_BUS_OUT_THRD_STACK_SZ]; +struct rt_prio_queue *_bus_out_que; + +static void _bus_out_entry(void *param) +{ + struct rt_vbus_pkg dpkg; + + _bus_out_que = rt_prio_queue_create("vbus", + _BUS_OUT_PKG_NR, + sizeof(struct rt_vbus_pkg)); + + if (!_bus_out_que) + { + rt_kprintf("could not create vmm bus queue\n"); + return; + } + + while (rt_prio_queue_pop(_bus_out_que, &dpkg, + RT_WAITING_FOREVER) == RT_EOK) + { + int sp; + rt_uint32_t nxtidx; + const int dnr = LEN2BNR(dpkg.len); + +#ifdef RT_VBUS_USING_FLOW_CONTROL + rt_wm_que_dec(&_chn_wm_que[dpkg.id]); +#endif + + if (!_chn_connected(dpkg.id)) + continue; + + sp = _bus_ring_space_nr(RT_VBUS_OUT_RING); + + vbus_debug("vmm bus out" + "(data: %p, len: %d, prio: %d, id: %d)\n", + dpkg.data, dpkg.len, dpkg.prio, dpkg.id); + + /* wait for enough space */ + while (sp < dnr) + { + rt_ubase_t lvl = rt_hw_interrupt_disable(); + + RT_VBUS_OUT_RING->blocked = 1; + rt_vbus_smp_wmb(); + + /* kick the guest, hoping this could force it do the work */ + rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ); + + rt_thread_suspend(rt_thread_self()); + rt_schedule(); + + RT_VBUS_OUT_RING->blocked = 0; + + rt_hw_interrupt_enable(lvl); + + sp = _bus_ring_space_nr(RT_VBUS_OUT_RING); + } + + nxtidx = RT_VBUS_OUT_RING->put_idx + dnr; + + RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].id = dpkg.id; + RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].qos = dpkg.prio; + RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].len = dpkg.len; + + if (nxtidx >= RT_VMM_RB_BLK_NR) + { + unsigned int tailsz; + + tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_OUT_RING->put_idx) + * sizeof(RT_VBUS_OUT_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ; + + /* the remaining block is sufficient for the data */ + if (tailsz > dpkg.len) + tailsz = dpkg.len; + + rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data, + dpkg.data, tailsz); + rt_memcpy(&RT_VBUS_OUT_RING->blks[0], + ((char*)dpkg.data)+tailsz, + dpkg.len - tailsz); + + rt_vbus_smp_wmb(); + RT_VBUS_OUT_RING->put_idx = nxtidx - RT_VMM_RB_BLK_NR; + } + else + { + rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data, + dpkg.data, dpkg.len); + + rt_vbus_smp_wmb(); + RT_VBUS_OUT_RING->put_idx = nxtidx; + } + + rt_vbus_smp_wmb(); + rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ); + + if (dpkg.finished) + { + _vbus_indicate(RT_VBUS_EVENT_ID_TX, dpkg.id); + } + } + RT_ASSERT(0); +} + +void rt_vbus_resume_out_thread(void) +{ + rt_thread_resume(&_bus_out_thread); + rt_schedule(); +} + +rt_err_t rt_vbus_post(rt_uint8_t id, + rt_uint8_t prio, + const void *data, + rt_size_t size, + rt_int32_t timeout) +{ + rt_err_t err = RT_EOK; + struct rt_vbus_pkg pkg; + unsigned int putsz; + const unsigned char *dp; + + if (!_bus_out_que) + { + rt_kprintf("post (data: %p, size: %d, timeout: %d) " + "to bus before initialition\n", + data, size, timeout); + return -RT_ERROR; + } + + if (id >= RT_VBUS_CHANNEL_NR) + return -RT_ERROR; + + if (timeout != 0) + { + RT_DEBUG_IN_THREAD_CONTEXT; + } + +#ifdef RT_VBUS_USING_FLOW_CONTROL + while (_chn_status[id] == RT_VBUS_CHN_ST_SUSPEND) + { + rt_thread_t thread; + + if (timeout == 0) + { + return -RT_EFULL; + } + + thread = rt_thread_self(); + thread->error = RT_EOK; + /* We only touch the _chn_suspended_threads in thread, so lock the + * scheduler is enough. */ + rt_enter_critical(); + rt_thread_suspend(thread); + + rt_list_insert_after(&_chn_suspended_threads[id], &thread->tlist); + if (timeout > 0) + { + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + /* rt_exit_critical will do schedule on need. */ + rt_exit_critical(); + + if (thread->error != RT_EOK) + return thread->error; + } +#endif + + if (_chn_status[id] != RT_VBUS_CHN_ST_ESTABLISHED) + return -RT_ERROR; + + dp = data; + pkg.id = id; + pkg.prio = prio; + for (putsz = 0; size; size -= putsz) + { + pkg.data = dp; + + if (size > RT_VBUS_MAX_PKT_SZ) + { + putsz = RT_VBUS_MAX_PKT_SZ; + pkg.finished = 0; + } + else + { + putsz = size; + pkg.finished = 1; + } + + pkg.len = putsz; + dp += putsz; + +#ifdef RT_VBUS_USING_FLOW_CONTROL + err = rt_wm_que_inc(&_chn_wm_que[id], timeout); + if (err != RT_EOK) + break; +#endif + + vbus_debug("post (data: %p(%d), size: %d, finshed: %d, timeout: %d)\n", + pkg.data, ((unsigned char*)pkg.data)[0], + pkg.len, pkg.finished, timeout); + + err = rt_prio_queue_push(_bus_out_que, prio, &pkg, timeout); + if (err != RT_EOK) + break; + } + + return err; +} + +struct rt_completion _chn0_post_cmp; + +void _chn0_tx_listener(void *p) +{ + rt_completion_done(&_chn0_post_cmp); +} + +/* Posts in channel0 should be sync. */ +static rt_err_t _chn0_post(const void *data, + rt_size_t size, + int timeout) +{ + rt_err_t err; + + rt_completion_init(&_chn0_post_cmp); + err = rt_vbus_post(0, 0, data, size, timeout); + if (err != RT_EOK) + return err; + return rt_completion_wait(&_chn0_post_cmp, timeout); +} + +#define _BUS_IN_THRD_STACK_SZ 1024 +#define _BUS_IN_THRD_PRIO (_BUS_OUT_THRD_PRIO+1) +#if (_BUS_IN_THRD_PRIO == RT_THREAD_PRIORITY_MAX) +#error "_BUS_OUT_THRD_PRIO too low" +#endif + +static struct rt_thread _bus_in_thread; +static rt_uint8_t _bus_in_thread_stack[_BUS_OUT_THRD_STACK_SZ]; +static struct rt_semaphore _bus_in_sem; +static struct rt_event _bus_in_event; +/* {head, tail} */ +#define _IN_ACT_HEAD 0 +#define _IN_ACT_TAIL 1 +static struct rt_vbus_data *_bus_in_action[RT_VBUS_CHANNEL_NR][2]; +#ifdef RT_VBUS_STATISTICS +static unsigned int _bus_in_action_nr[RT_VBUS_CHANNEL_NR]; +#endif + +static void rt_vbus_notify_chn(unsigned char chnr, rt_err_t err) +{ +#ifdef RT_VBUS_USING_FLOW_CONTROL + /* TODO: get rid of this */ + /* Protect the list. */ + rt_enter_critical(); + while (!rt_list_isempty(&_chn_suspended_threads[chnr])) + { + rt_thread_t thread; + + thread = rt_list_entry(_chn_suspended_threads[chnr].next, + struct rt_thread, + tlist); + thread->error = err; + rt_thread_resume(thread); + } + rt_exit_critical(); +#endif + rt_event_send(&_bus_in_event, 1 << chnr); +} + +static void rt_vbus_notify_set(rt_uint32_t set) +{ + rt_event_send(&_bus_in_event, set); +} + +rt_err_t rt_vbus_listen_on(rt_uint8_t chnr, + rt_int32_t timeout) +{ + rt_uint32_t notuse; + + if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR || !_chn_connected(chnr)) + return -RT_EIO; + + return rt_event_recv(&_bus_in_event, 1 << chnr, + RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, + timeout, ¬use); +} + +void rt_vbus_data_push(unsigned int id, struct rt_vbus_data *act) +{ + rt_ubase_t lvl; + + RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR); + + lvl = rt_hw_interrupt_disable(); + + if (_bus_in_action[id][_IN_ACT_HEAD] == RT_NULL) + { + _bus_in_action[id][_IN_ACT_HEAD] = act; + _bus_in_action[id][_IN_ACT_TAIL] = act; + } + else + { + _bus_in_action[id][_IN_ACT_TAIL]->next = act; + _bus_in_action[id][_IN_ACT_TAIL] = act; + } + +#ifdef RT_VBUS_STATISTICS + _bus_in_action_nr[id]++; +#endif + + rt_hw_interrupt_enable(lvl); + +#ifdef RT_VBUS_USING_FLOW_CONTROL + _chn_recv_wm[id].level++; + if (_chn_recv_wm[id].level == 0) + _chn_recv_wm[id].level = ~0; + if (_chn_recv_wm[id].level > _chn_recv_wm[id].high_mark && + _chn_recv_wm[id].level > _chn_recv_wm[id].last_warn) + { + unsigned char buf[2]; + + buf[0] = RT_VBUS_CHN0_CMD_SUSPEND; + buf[1] = id; + vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf))); + _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER); + /* Warn the other side in 100 more pkgs. */ + _chn_recv_wm[id].last_warn = _chn_recv_wm[id].level + 100; + } +#endif +} + +struct rt_vbus_data* rt_vbus_data_pop(unsigned int id) +{ + struct rt_vbus_data *act; + rt_ubase_t lvl; + + RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR); + + lvl = rt_hw_interrupt_disable(); + + act = _bus_in_action[id][_IN_ACT_HEAD]; + if (act) + { + _bus_in_action[id][_IN_ACT_HEAD] = act->next; + } + + rt_hw_interrupt_enable(lvl); + +#ifdef RT_VBUS_USING_FLOW_CONTROL + if (_chn_recv_wm[id].level != 0) + { + _chn_recv_wm[id].level--; + if (_chn_recv_wm[id].level <= _chn_recv_wm[id].low_mark && + _chn_recv_wm[id].last_warn > _chn_recv_wm[id].low_mark) + { + unsigned char buf[2]; + + buf[0] = RT_VBUS_CHN0_CMD_RESUME; + buf[1] = id; + vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf))); + _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER); + _chn_recv_wm[id].last_warn = 0; + } + } +#endif + return act; +} + +/* dump cmd that is not start with ACK/NAK */ +static size_t __dump_naked_cmd(char *dst, size_t lsize, + unsigned char *dp, size_t dsize) +{ + size_t len; + if (dp[0] == RT_VBUS_CHN0_CMD_DISABLE || + dp[0] == RT_VBUS_CHN0_CMD_SUSPEND || + dp[0] == RT_VBUS_CHN0_CMD_RESUME) + { + len = rt_snprintf(dst, lsize, "%s %d", + rt_vbus_cmd2str[dp[0]], dp[1]); + } + else if (dp[0] == RT_VBUS_CHN0_CMD_ENABLE) + { + len = rt_snprintf(dst, lsize, "%s %s", + rt_vbus_cmd2str[dp[0]], dp+1); + } + else if (dp[0] < RT_VBUS_CHN0_CMD_MAX) + { + len = rt_snprintf(dst, lsize, "%s %s %d", + rt_vbus_cmd2str[dp[0]], + dp+1, dp[2+rt_strlen((char*)dp+1)]); + } + else + { + len = rt_snprintf(dst, lsize, "(invalid)%d %d", + dp[0], dp[1]); + } + return len; +} + +static char _cmd_dump_buf[64]; +static char* dump_cmd_pkt(unsigned char *dp, size_t dsize) +{ + size_t len; + + if (dp[0] == RT_VBUS_CHN0_CMD_ACK || dp[0] == RT_VBUS_CHN0_CMD_NAK ) + { + len = rt_snprintf(_cmd_dump_buf, sizeof(_cmd_dump_buf), + "%s ", rt_vbus_cmd2str[dp[0]]); + len += __dump_naked_cmd(_cmd_dump_buf+len, sizeof(_cmd_dump_buf)-len, + dp+1, dsize-1); + } + else + { + len = __dump_naked_cmd(_cmd_dump_buf, sizeof(_cmd_dump_buf), + dp, dsize); + } + + if (len > sizeof(_cmd_dump_buf) - 1) + len = sizeof(_cmd_dump_buf) - 1; + + _cmd_dump_buf[len] = '\0'; + return _cmd_dump_buf; +} + +static rt_err_t _chn0_echo_with(rt_uint8_t prefix, + rt_uint32_t dsize, + unsigned char *dp) +{ + rt_err_t err; + unsigned char *resp; + + resp = rt_malloc(dsize+1); + if (!resp) + return -RT_ENOMEM; + *resp = prefix; + rt_memcpy(resp+1, dp, dsize); + vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1)); + + err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER); + + rt_free(resp); + + return err; +} + +static rt_err_t _chn0_nak(rt_uint32_t dsize, unsigned char *dp) +{ + return _chn0_echo_with(RT_VBUS_CHN0_CMD_NAK, dsize, dp); +} + +static rt_err_t _chn0_ack(rt_uint32_t dsize, unsigned char *dp) +{ + return _chn0_echo_with(RT_VBUS_CHN0_CMD_ACK, dsize, dp); +} + +enum _vbus_session_st +{ + SESSIOM_AVAILABLE, + SESSIOM_LISTENING, + SESSIOM_ESTABLISHING, +}; + +struct rt_vbus_conn_session +{ + /* negative value means error */ + int chnr; + enum _vbus_session_st st; + struct rt_completion cmp; + struct rt_vbus_request *req; +}; + +static struct rt_vbus_conn_session _sess[RT_VBUS_CHANNEL_NR/2]; + +static int _sess_find(const unsigned char *name, + enum _vbus_session_st st) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(_sess); i++) + { + if (_sess[i].st == st && _sess[i].req->name && + rt_strcmp(_sess[i].req->name, (char*)name) == 0) + break; + } + return i; +} + +static int _chn0_actor(unsigned char *dp, size_t dsize) +{ + if (*dp != RT_VBUS_CHN0_CMD_SUSPEND && *dp != RT_VBUS_CHN0_CMD_RESUME) + vbus_verbose("local <-- %s\n", dump_cmd_pkt(dp, dsize)); + + switch (*dp) + { + case RT_VBUS_CHN0_CMD_ENABLE: + { + int i, chnr; + rt_err_t err; + unsigned char *resp; + + i = _sess_find(dp+1, SESSIOM_LISTENING); + if (i == ARRAY_SIZE(_sess)) + { + _chn0_nak(dsize, dp); + break; + } + + for (chnr = 0; chnr < ARRAY_SIZE(_chn_status); chnr++) + { + if (_chn_status[chnr] == RT_VBUS_CHN_ST_AVAILABLE) + break; + } + if (chnr == ARRAY_SIZE(_chn_status)) + { + _chn0_nak(dsize, dp); + break; + } + + resp = rt_malloc(dsize + 1); + if (!resp) + break; + + *resp = RT_VBUS_CHN0_CMD_SET; + rt_memcpy(resp+1, dp+1, dsize-1); + resp[dsize] = chnr; + + rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high); + rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high); + + vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1)); + err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER); + + if (err == RT_EOK) + { + _sess[i].st = SESSIOM_ESTABLISHING; + vbus_debug("set sess %d st: %s\n", i, + rt_vbus_sess_st2str[_sess[i].st]); + _sess[i].chnr = chnr; + _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHING; + } + rt_free(resp); + } + break; + case RT_VBUS_CHN0_CMD_SET: + { + int i, chnr; + + i = _sess_find(dp+1, SESSIOM_ESTABLISHING); + if (i == ARRAY_SIZE(_sess)) + { + vbus_verbose("drop spurious packet\n"); + break; + } + + chnr = dp[1+rt_strlen((const char*)dp+1)+1]; + + if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) + { + vbus_verbose("SET wrong chnr %d\n", chnr); + break; + } + if (_chn_status[chnr] != RT_VBUS_CHN_ST_AVAILABLE) + { + _chn0_nak(dsize, dp); + vbus_verbose("SET wrong chnr status %d, %s\n", + chnr, rt_vbus_chn_st2str[_chn_status[chnr]]); + break; + } + + rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high); + rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high); + + if (_chn0_ack(dsize, dp) >= 0) + { + _sess[i].chnr = chnr; + _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED; + vbus_debug("chn %d %s\n", chnr, + rt_vbus_chn_st2str[_chn_status[chnr]]); + rt_completion_done(&_sess[i].cmp); + } + } + break; + case RT_VBUS_CHN0_CMD_ACK: + if (dp[1] == RT_VBUS_CHN0_CMD_SET) + { + int i, chnr; + + i = _sess_find(dp+2, SESSIOM_ESTABLISHING); + if (i == ARRAY_SIZE(_sess)) + /* drop that spurious packet */ + break; + + chnr = dp[1+rt_strlen((const char*)dp+2)+2]; + + _sess[i].chnr = chnr; + _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED; + vbus_debug("chn %d %s\n", chnr, + rt_vbus_chn_st2str[_chn_status[chnr]]); + rt_completion_done(&_sess[i].cmp); + } + else if (dp[1] == RT_VBUS_CHN0_CMD_DISABLE) + { + unsigned char chnr = dp[2]; + + if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) + break; + + /* We could only get here by sending DISABLE command, which is + * initiated by the rt_vbus_close_chn. */ + _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE; + + _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr); + /* notify the thread that the channel has been closed */ + rt_vbus_notify_chn(chnr, -RT_ERROR); + } + else + { + vbus_info("invalid ACK for %d\n", dp[1]); + } + break; + case RT_VBUS_CHN0_CMD_DISABLE: + { + unsigned char chnr = dp[1]; + + if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) + break; + + _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING; + + _chn0_ack(dsize, dp); + + _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr); + /* notify the thread that the channel has been closed */ + rt_vbus_notify_chn(chnr, -RT_ERROR); + } + break; + case RT_VBUS_CHN0_CMD_SUSPEND: +#ifdef RT_VBUS_USING_FLOW_CONTROL + { + unsigned char chnr = dp[1]; + + if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) + break; + + if (_chn_status[chnr] != RT_VBUS_CHN_ST_ESTABLISHED) + break; + + _chn_status[chnr] = RT_VBUS_CHN_ST_SUSPEND; + } +#endif + break; + case RT_VBUS_CHN0_CMD_RESUME: +#ifdef RT_VBUS_USING_FLOW_CONTROL + { + unsigned char chnr = dp[1]; + + if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR) + break; + + if (_chn_status[chnr] != RT_VBUS_CHN_ST_SUSPEND) + break; + + _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED; + + /* Protect the list. */ + rt_enter_critical(); + while (!rt_list_isempty(&_chn_suspended_threads[chnr])) + { + rt_thread_t thread; + + thread = rt_list_entry(_chn_suspended_threads[chnr].next, + struct rt_thread, + tlist); + rt_thread_resume(thread); + } + rt_exit_critical(); + } +#endif + break; + case RT_VBUS_CHN0_CMD_NAK: + if (dp[1] == RT_VBUS_CHN0_CMD_ENABLE) + { + int i; + + i = _sess_find(dp+2, SESSIOM_ESTABLISHING); + if (i == ARRAY_SIZE(_sess)) + /* drop that spurious packet */ + break; + + _sess[i].chnr = -RT_EIO; + rt_completion_done(&_sess[i].cmp); + } + else if (dp[1] == RT_VBUS_CHN0_CMD_SET) + { + vbus_info("NAK for %d not implemented\n", dp[1]); + } + else + { + vbus_info("invalid NAK for %d\n", dp[1]); + } + break; + default: + /* just ignore the invalid cmd */ + vbus_info("drop unknown cmd %d on chn0\n", *dp); + break; + }; + + return RT_EOK; +} + +int rt_vbus_request_chn(struct rt_vbus_request *req, + int timeout) +{ + int i, chnr, err; + size_t plen = rt_strlen(req->name) + 2; + unsigned char *pbuf; + rt_ubase_t lvl; + + lvl = rt_hw_interrupt_disable(); + for (i = 0; i < ARRAY_SIZE(_sess); i++) + { + if (_sess[i].st == SESSIOM_AVAILABLE) + break; + } + if (i == ARRAY_SIZE(_sess)) + { + rt_hw_interrupt_enable(lvl); + return -RT_ERROR; + } + + rt_completion_init(&_sess[i].cmp); + _sess[i].req = req; + + if (req->is_server) + { + _sess[i].st = SESSIOM_LISTENING; + rt_hw_interrupt_enable(lvl); + + vbus_debug("request listening %s on %d\n", req->name, i); + + /* always wait on the condition */ + err = RT_EOK; + goto _waitforcmp; + } + + pbuf = rt_malloc(plen); + if (!pbuf) + { + rt_hw_interrupt_enable(lvl); + return -RT_ENOMEM; + } + + _sess[i].st = SESSIOM_ESTABLISHING; + rt_hw_interrupt_enable(lvl); + + pbuf[0] = RT_VBUS_CHN0_CMD_ENABLE; + rt_memcpy(pbuf+1, req->name, plen-1); + vbus_verbose("%s --> remote\n", dump_cmd_pkt(pbuf, plen)); + + err = _chn0_post(pbuf, plen, RT_WAITING_FOREVER); + rt_free(pbuf); + +_waitforcmp: + if (err == RT_EOK) + err = rt_completion_wait(&_sess[i].cmp, timeout); + + vbus_debug("request wait cmp done %d, chnr %d\n", err, _sess[i].chnr); + + if (err) + { + /* cleanup the mass when the wait is time out but we have done some job + */ + if (_sess[i].st == SESSIOM_ESTABLISHING) + _chn_status[_sess[i].chnr] = RT_VBUS_CHN_ST_AVAILABLE; + chnr = err; + goto Out; + } + + RT_ASSERT(_sess[i].chnr != 0); + + chnr = _sess[i].chnr; + +Out: + /* detach the sess as we finished the job */ + _sess[i].st = SESSIOM_AVAILABLE; + _sess[i].req = RT_NULL; + + return chnr; +} + +void rt_vbus_close_chn(unsigned char chnr) +{ + void *p; + rt_err_t err; + unsigned char buf[2]; + + buf[0] = RT_VBUS_CHN0_CMD_DISABLE; + buf[1] = chnr; + + RT_ASSERT(0 < chnr && chnr < RT_VBUS_CHANNEL_NR); + + if (_chn_status[chnr] == RT_VBUS_CHN_ST_CLOSED || + _chn_status[chnr] == RT_VBUS_CHN_ST_CLOSING) + { + _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE; + return; + } + + if (!_chn_connected(chnr)) + return; + + _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING; + vbus_info("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf))); + err = _chn0_post(&buf, sizeof(buf), RT_WAITING_FOREVER); + if (err == RT_EOK) + /* wait for the ack */ + rt_vbus_listen_on(chnr, 10 * RT_TICK_PER_SECOND); + + /* cleanup the remaining data */ + for (p = rt_vbus_data_pop(chnr); p; p = rt_vbus_data_pop(chnr)) + rt_free(p); + /* FIXME: there is a chance that there are some data left on the send + * buffer. So if we connect other channel with the same number immediately, + * the new channel will receive some garbage data. However, this is highly + * un-probable. */ +} + +#ifdef RT_VBUS_STATISTICS +static unsigned int _total_data_sz; +#endif + +static void _bus_in_entry(void *param) +{ + rt_sem_init(&_bus_in_sem, "vbus", 0, RT_IPC_FLAG_FIFO); + rt_event_init(&_bus_in_event, "vbus", RT_IPC_FLAG_FIFO); + rt_memset(_bus_in_action, 0, sizeof(_bus_in_action)); + + while (rt_sem_take(&_bus_in_sem, + RT_WAITING_FOREVER) == RT_EOK) + { + rt_uint32_t event_set = 0; + + /* while(not empty) */ + while (RT_VBUS_IN_RING->get_idx != RT_VBUS_IN_RING->put_idx) + { + unsigned int id, nxtidx; + rt_size_t size; + struct rt_vbus_data *act; + + rt_vbus_smp_rmb(); + size = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].len; + id = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].id; + + vbus_debug("vmm bus in: chnr %d, size %d\n", id, size); + + /* Suspended channel can still recv data. */ + if (id > RT_VBUS_CHANNEL_NR || !_chn_connected(id)) + { + vbus_error("drop on invalid chn %d\n", id); + /* drop the invalid packet */ + _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size)); + continue; + } + + if (id == 0) + { + if (size > 60) + vbus_error("too big(%d) packet on chn0\n", size); + else + _chn0_actor(RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size); + _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size)); + continue; + } + +#ifdef RT_VBUS_STATISTICS + _total_data_sz += size; +#endif + + act = rt_malloc(sizeof(*act) + size); + if (act == RT_NULL) + { + //vbus_error("drop on OOM (%d, %d)\n", id, size); + /* drop the packet on malloc fall */ + _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size)); + continue; + } + + act->size = size; + act->next = RT_NULL; + + nxtidx = RT_VBUS_IN_RING->get_idx + LEN2BNR(size); + if (nxtidx >= RT_VMM_RB_BLK_NR) + { + unsigned int tailsz; + + tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_IN_RING->get_idx) + * sizeof(RT_VBUS_IN_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ; + + /* the remaining block is sufficient for the data */ + if (tailsz > size) + tailsz = size; + + rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, tailsz); + rt_memcpy((char*)(act+1) + tailsz, &RT_VBUS_IN_RING->blks[0], size - tailsz); + + /* It shall make sure the CPU has finished reading the item + * before it writes the new tail pointer, which will erase the + * item. */ + rt_vbus_smp_wmb(); + RT_VBUS_IN_RING->get_idx = nxtidx - RT_VMM_RB_BLK_NR; + } + else + { + rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size); + + rt_vbus_smp_wmb(); + RT_VBUS_IN_RING->get_idx = nxtidx; + } + + rt_vbus_data_push(id, act); + _vbus_indicate(RT_VBUS_EVENT_ID_RX, id); + event_set |= 1 << id; + + if (RT_VBUS_IN_RING->blocked) + rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ); + } + + if (event_set != 0) + rt_vbus_notify_set(event_set); + } + RT_ASSERT(0); +} + +void rt_vbus_isr(int irqnr, void *param) +{ + if (RT_VBUS_OUT_RING->blocked) + rt_vbus_resume_out_thread(); + + rt_sem_release(&_bus_in_sem); + rt_vbus_hw_eoi(irqnr, param); +} + +int rt_vbus_init(void *outr, void *inr) +{ + int i; + +#ifdef RT_USING_LOGTRACE + log_trace_register_session(&_lgs); +#endif + + if (outr > inr) + { + RT_ASSERT((char*)outr - (char*)inr >= sizeof(struct rt_vbus_ring)); + } + else + { + RT_ASSERT((char*)inr - (char*)outr >= sizeof(struct rt_vbus_ring)); + } + + RT_VBUS_OUT_RING = outr; + RT_VBUS_IN_RING = inr; + + rt_memset(RT_VBUS_OUT_RING, 0, sizeof(*RT_VBUS_OUT_RING)); + rt_memset(RT_VBUS_IN_RING, 0, sizeof(*RT_VBUS_IN_RING)); + _chn_status[0] = RT_VBUS_CHN_ST_ESTABLISHED; + for (i = 1; i < ARRAY_SIZE(_chn_status); i++) + { + _chn_status[i] = RT_VBUS_CHN_ST_AVAILABLE; + } + for (i = 0; i < ARRAY_SIZE(_sess); i++) + { + _sess[i].req = RT_NULL; + _sess[i].st = SESSIOM_AVAILABLE; + } + _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].indicate = _chn0_tx_listener; + _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].ctx = RT_NULL; + +#ifdef RT_VBUS_USING_FLOW_CONTROL + for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++) + { + rt_wm_que_init(&_chn_wm_que[i], + RT_VMM_RB_BLK_NR / 3, + RT_VMM_RB_BLK_NR * 2 / 3); + } + /* Channel 0 has the full channel. */ + rt_wm_que_set_mark(&_chn_wm_que[0], 0, ~0); + + for (i = 0; i < ARRAY_SIZE(_chn_suspended_threads); i++) + { + rt_list_init(&_chn_suspended_threads[i]); + } + + for (i = 1; i < ARRAY_SIZE(_chn_recv_wm); i++) + { + rt_vbus_set_recv_wm(i, + RT_VMM_RB_BLK_NR / 3, + RT_VMM_RB_BLK_NR * 2 / 3); + _chn_recv_wm[i].level = 0; + _chn_recv_wm[i].last_warn = 0; + } + /* Channel 0 has the full channel. Don't suspend it. */ + _chn_recv_wm[0].low_mark = 0; + _chn_recv_wm[0].high_mark = ~0; + _chn_recv_wm[0].level = 0; + _chn_recv_wm[0].last_warn = 0; +#endif + + rt_thread_init(&_bus_out_thread, "vbusout", + _bus_out_entry, RT_NULL, + _bus_out_thread_stack, sizeof(_bus_out_thread_stack), + _BUS_OUT_THRD_PRIO, 20); + rt_thread_startup(&_bus_out_thread); + + rt_thread_init(&_bus_in_thread, "vbusin", + _bus_in_entry, RT_NULL, + _bus_in_thread_stack, sizeof(_bus_in_thread_stack), + _BUS_IN_THRD_PRIO, 20); + + + rt_thread_startup(&_bus_in_thread); + + rt_vbus_hw_init(); + + rt_kprintf("VBus loaded: %d out blocks, %d in blocks\n", + RT_VMM_RB_BLK_NR, RT_VMM_RB_BLK_NR); + + rt_vbus_chnx_init(); + + return 0; +} + +void rt_vbus_rb_dump(void) +{ + rt_kprintf("OUT ring:(%s blocked)\n", RT_VBUS_OUT_RING->blocked ? "is" : "not"); + rt_kprintf("put idx: %8x, get idx: %8x\n", + RT_VBUS_OUT_RING->put_idx, RT_VBUS_OUT_RING->get_idx); + rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_OUT_RING)); + + + rt_kprintf("IN ring:(%s blocked)\n", RT_VBUS_IN_RING->blocked ? "is" : "not"); + rt_kprintf("put idx: %8x, get idx: %8x\n", + RT_VBUS_IN_RING->put_idx, RT_VBUS_IN_RING->get_idx); + rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_IN_RING)); +} + +void rt_vbus_chn_dump(void) +{ + int i; + rt_kprintf("vbus channel status:\n"); + for (i = 0; i < ARRAY_SIZE(_chn_status); i++) + { + rt_kprintf("%2d:%s\n", i, rt_vbus_chn_st2str[_chn_status[i]]); + } +} + +void rt_vbus_sess_dump(void) +{ + int i; + + rt_kprintf("vbus conn session:\n"); + for (i = 0; i < ARRAY_SIZE(_sess); i++) + { + rt_kprintf("%2d(%s):%s\n", i, _sess[i].req ? _sess[i].req->name : "", + rt_vbus_sess_st2str[_sess[i].st]); + } +} + +void rt_vbus_que_dump(void) +{ + rt_kprintf("out que:\n"); + rt_prio_queue_dump(_bus_out_que); +} + +unsigned int rt_vbus_total_data_sz(void) +{ +#ifdef RT_VBUS_STATISTICS + return _total_data_sz; +#else + return (unsigned int)-1; +#endif +} + +void rt_vbus_data_pkt_dump(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(_bus_in_action); i++) + { + struct rt_vbus_data *dp; + +#ifdef RT_VBUS_STATISTICS + rt_kprintf("%2d %4d: ", i, _bus_in_action_nr[i]); +#else + rt_kprintf("%2d: ", i); +#endif + for (dp = _bus_in_action[i][_IN_ACT_HEAD]; + dp; + dp = dp->next) + { + rt_kprintf("%p(%d) -> ", dp, dp->size); + } + rt_kprintf(" nil\n"); + } +} + +#ifdef RT_VBUS_USING_FLOW_CONTROL +void rt_vbus_chm_wm_dump(void) +{ + int i; + + rt_kprintf("post wm:\n"); + for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++) + rt_wm_que_dump(&_chn_wm_que[i]); + + rt_kprintf("recv wm:\n"); + rt_kprintf(" low, high, cur, last warn\n"); + for (i = 0; i < ARRAY_SIZE(_chn_recv_wm); i++) + { + rt_kprintf("%8x, %8x, %8x, %8x\n", + _chn_recv_wm[i].low_mark, _chn_recv_wm[i].high_mark, + _chn_recv_wm[i].level, _chn_recv_wm[i].last_warn); + } +} +#endif + +#ifdef RT_USING_FINSH +#include +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_rb_dump, vbrb, dump vbus ringbuffer status); +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chn_dump, vbchn, dump vbus channel status); +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_sess_dump, vbses, dump vbus session status); +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_que_dump, vbque, dump vbus out queue status); +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_total_data_sz, vbtsz, total in data); +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_data_pkt_dump, vbdq, dump the data queue); +#ifdef RT_VBUS_USING_FLOW_CONTROL +FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chm_wm_dump, vbwm, dump vbus water mark status); +#endif +#endif + diff --git a/components/vbus/vbus.h b/components/vbus/vbus.h new file mode 100644 index 0000000000000000000000000000000000000000..2187773a4791818d3608b5c7a27b992ff9765d33 --- /dev/null +++ b/components/vbus/vbus.h @@ -0,0 +1,197 @@ +#ifndef __VBUS_H__ +#define __VBUS_H__ +/* + * VBus + * + * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-06-09 Grissiom version 2.0.2; add comment + * 2015-01-06 Grissiom version 2.0.3; API change, no functional changes + */ + +#include "vbus_local_conf.h" +#include + +int rt_vbus_init(void *outr, void *inr); + +void rt_vbus_resume_out_thread(void); + +/** Post data on channel. + * + * @param chnr the channel number + * @param prio the priority of the data + * @param datap pointer to the actual data + * @param size number of byte of the data + * @param timeout the value used in the blocking API + * + * Note: rt_vbus_post is an asynchronous function that when it returns, the + * @datap and @size is recorded in the post queue at least but there is no + * guarantee that the data is copied into the ring buffer. To avoid data + * corruption, you need to wait on the RT_VBUS_EVENT_ID_TX event. + * + * However, if you just post static data such as static string, there is no + * need to wait. + * + * @sa rt_vbus_register_listener . + */ +rt_err_t rt_vbus_post(rt_uint8_t chnr, + rt_uint8_t prio, + const void *datap, + rt_size_t size, + rt_int32_t timeout); + +struct rt_vbus_data { + /* Number of bytes in current data package. */ + unsigned char size; + /* Used internally in VBus. Don't modify this field as it may corrupt the + * receive queue. */ + struct rt_vbus_data *next; + /* Data follows the struct */ +}; + +struct rt_vbus_wm_cfg { + unsigned int low, high; +}; + +struct rt_vbus_request { + unsigned char prio; + const char *name; + int is_server; + struct rt_vbus_wm_cfg recv_wm, post_wm; +}; + +/** Request a channel. + * + * @return channel number. Negative if error happened. + */ +int rt_vbus_request_chn(struct rt_vbus_request *req, int timeout); + +/** Close channel @chnr */ +void rt_vbus_close_chn(unsigned char chnr); + +/** Set the water mark level for posting into the channel @chnr. */ +void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high); +/** Set the water mark level for receiving from the channel @chnr. */ +void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high); + +typedef void (*rt_vbus_event_listener)(void *ctx); + +enum rt_vbus_event_id { + /* On a packet received in channel. */ + RT_VBUS_EVENT_ID_RX, + /* On the data of rt_vbus_post has been written to the ring buffer. */ + RT_VBUS_EVENT_ID_TX, + /* On the channel has been closed. */ + RT_VBUS_EVENT_ID_DISCONN, + RT_VBUS_EVENT_ID_MAX, +}; + +/** Register callback @indi on the event @eve on the @chnr. + * + * @ctx will passed to @indi on calling the @indi. + */ +void rt_vbus_register_listener(unsigned char chnr, + enum rt_vbus_event_id eve, + rt_vbus_event_listener indi, + void *ctx); + +/** Listen on any events happen on the @chnr for @timeout ticks. + * + * This function blocks until events occur or timeout happened. + */ +rt_err_t rt_vbus_listen_on(rt_uint8_t chnr, + rt_int32_t timeout); + +/** Push a data package into the receive queue of the channel @chnr. */ +void rt_vbus_data_push(unsigned int chnr, + struct rt_vbus_data *data); +/** Pop a data package from the receive queue of the channel @chnr. + * + * The actual data is following the struct rt_vbus_data. After using it, it + * should be freed by rt_free. + */ +struct rt_vbus_data* rt_vbus_data_pop(unsigned int chnr); + +struct rt_vbus_dev +{ + /* Runtime infomations. */ + rt_uint8_t chnr; + struct rt_vbus_data *act; + rt_size_t pos; + + /* There will be a request for each channel. So no need to seperate them so + * clearly. */ + struct rt_vbus_request req; +}; + +rt_err_t rt_vbus_chnx_init(void); +/** Get the corresponding channel number from the VBus device @dev. */ +rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev); +/** Register a call back on the other side disconnect the channel. + * + * @sa rt_vbus_register_listener . + */ +void rt_vbus_chnx_register_disconn(rt_device_t dev, + rt_vbus_event_listener indi, + void *ctx); + +/* Commands for the device control interface. */ +#define VBUS_IOCRECV_WM 0xD1 +#define VBUS_IOCPOST_WM 0xD2 +/** Configure event listener */ +#define VBUS_IOC_LISCFG 0xD3 + +struct rt_vbus_dev_liscfg +{ + enum rt_vbus_event_id event; + rt_vbus_event_listener listener; + void *ctx; +}; + +int rt_vbus_shell_start(void); +#ifdef RT_USING_VBUS_RFS +int dfs_rfs_init(void); +#endif + +/** VBus hardware init function. + * + * BSP should implement this function to initialize the interrupts etc. + */ +int rt_vbus_hw_init(void); + +/** VBus ISR function. + * + * BSP should call this function when the interrupt from other core is + * triggered. @param is not used by VBus and will pass to rt_vbus_hw_eoi. + */ +void rt_vbus_isr(int irqnr, void *param); + +/** VBus End Of Interrupt function. + * + * This function will be called when VBus finished the ISR handling. BSP should + * define this function to clear the interrupt flag etc. + */ +int rt_vbus_hw_eoi(int irqnr, void *param); + +#endif /* end of include guard: __VBUS_H__ */ diff --git a/components/vbus/vbus_chnx.c b/components/vbus/vbus_chnx.c new file mode 100644 index 0000000000000000000000000000000000000000..bd54c9dbbd247e38d3f6e900433f9bcdc05f6740 --- /dev/null +++ b/components/vbus/vbus_chnx.c @@ -0,0 +1,287 @@ +/* + * Channel on VMM Bus + * + * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd + * http://www.rt-thread.com + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-11-04 Grissiom add comment + */ + +#include +#include +#include + +#include "vbus.h" + +static void _rx_indicate(void *ctx) +{ + rt_device_t dev = ctx; + + if (dev->rx_indicate) + dev->rx_indicate(dev, 0); +} + +static void _tx_complete(void *ctx) +{ + rt_device_t dev = ctx; + + if (dev->tx_complete) + dev->tx_complete(dev, 0); +} + +static rt_err_t _open(rt_device_t dev, rt_uint16_t oflag) +{ + int chnr; + struct rt_vbus_dev *vdev = dev->user_data; + + if (vdev->chnr) + return RT_EOK; + + /* FIXME: request the same name for twice will crash */ + chnr = rt_vbus_request_chn(&vdev->req, RT_WAITING_FOREVER); + if (chnr < 0) + return chnr; + + vdev->chnr = chnr; + rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_RX, _rx_indicate, dev); + rt_vbus_register_listener(chnr, RT_VBUS_EVENT_ID_TX, _tx_complete, dev); + + return RT_EOK; +} + +static rt_err_t _close(rt_device_t dev) +{ + struct rt_vbus_dev *vdev = dev->user_data; + + RT_ASSERT(vdev->chnr != 0); + + rt_vbus_close_chn(vdev->chnr); + vdev->chnr = 0; + + return RT_EOK; +} + +static rt_size_t _read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + rt_size_t outsz = 0; + struct rt_vbus_dev *vdev = dev->user_data; + + RT_ASSERT(vdev->chnr != 0); + + if (vdev->act == RT_NULL) + { + vdev->act = rt_vbus_data_pop(vdev->chnr); + vdev->pos = 0; + } + + while (1) + { + rt_err_t err; + + while (vdev->act) + { + rt_size_t cpysz; + + if (size - outsz > vdev->act->size - vdev->pos) + cpysz = vdev->act->size - vdev->pos; + else + cpysz = size - outsz; + + rt_memcpy((char*)buffer + outsz, ((char*)(vdev->act+1)) + vdev->pos, cpysz); + vdev->pos += cpysz; + + outsz += cpysz; + if (outsz == size) + { + return outsz; + } + else if (outsz > size) + RT_ASSERT(0); + + /* free old and get new */ + rt_free(vdev->act); + vdev->act = rt_vbus_data_pop(vdev->chnr); + vdev->pos = 0; + } + + /* TODO: We don't want to touch the rx_indicate here. But this lead to + * some duplication. Maybe we should find a better way to handle this. + */ + if (rt_interrupt_get_nest() == 0) + { + err = rt_vbus_listen_on(vdev->chnr, RT_WAITING_FOREVER); + } + else + { + err = rt_vbus_listen_on(vdev->chnr, 0); + } + if (err != RT_EOK) + { + rt_set_errno(err); + return outsz; + } + vdev->act = rt_vbus_data_pop(vdev->chnr); + vdev->pos = 0; + } +} + +static rt_size_t _write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_err_t err; + struct rt_vbus_dev *vdev = dev->user_data; + + RT_ASSERT(vdev->chnr != 0); + + if (rt_interrupt_get_nest() == 0) + { + /* Thread context. */ + err = rt_vbus_post(vdev->chnr, vdev->req.prio, + buffer, size, RT_WAITING_FOREVER); + } + else + { + /* Interrupt context. */ + err = rt_vbus_post(vdev->chnr, vdev->req.prio, + buffer, size, 0); + } + + if (err) + { + rt_set_errno(err); + return 0; + } + + return size; +} + +rt_err_t _control(rt_device_t dev, rt_uint8_t cmd, void *args) +{ + RT_ASSERT(dev); + + switch (cmd) { + case VBUS_IOC_LISCFG: { + struct rt_vbus_dev *vdev = dev->user_data; + struct rt_vbus_dev_liscfg *liscfg = args; + + RT_ASSERT(vdev->chnr != 0); + if (!liscfg) + return -RT_ERROR; + + rt_vbus_register_listener(vdev->chnr, liscfg->event, + liscfg->listener, liscfg->ctx); + return RT_EOK; + } + break; +#ifdef RT_VBUS_USING_FLOW_CONTROL + case VBUS_IOCRECV_WM: { + struct rt_vbus_dev *vdev = dev->user_data; + struct rt_vbus_wm_cfg *cfg; + + RT_ASSERT(vdev->chnr != 0); + + if (!args) + return -RT_ERROR; + + cfg = (struct rt_vbus_wm_cfg*)args; + if (cfg->low > cfg->high) + return -RT_ERROR; + + rt_vbus_set_recv_wm(vdev->chnr, cfg->low, cfg->high); + return RT_EOK; + } + break; + case VBUS_IOCPOST_WM: { + struct rt_vbus_dev *vdev = dev->user_data; + struct rt_vbus_wm_cfg *cfg; + + RT_ASSERT(vdev->chnr != 0); + + if (!args) + return -RT_ERROR; + + cfg = (struct rt_vbus_wm_cfg*)args; + if (cfg->low > cfg->high) + return -RT_ERROR; + + rt_vbus_set_post_wm(vdev->chnr, cfg->low, cfg->high); + return RT_EOK; + } + break; +#endif + default: + break; + }; + + return -RT_ENOSYS; +} + +rt_uint8_t rt_vbus_get_chnnr(rt_device_t dev) +{ + struct rt_vbus_dev *vdev; + + RT_ASSERT(dev); + + vdev = dev->user_data; + + return vdev->chnr; +} + +void rt_vbus_chnx_register_disconn(rt_device_t dev, + rt_vbus_event_listener indi, + void *ctx) +{ + struct rt_vbus_dev *vdev = dev->user_data; + + RT_ASSERT(vdev->chnr != 0); + + if (vdev) + rt_vbus_register_listener(vdev->chnr, RT_VBUS_EVENT_ID_DISCONN, + indi, ctx); +} + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +extern struct rt_vbus_dev rt_vbus_chn_devx[]; +static struct rt_device _devx[32]; + +rt_err_t rt_vbus_chnx_init(void) +{ + int i; + struct rt_vbus_dev *p; + + for (i = 0, p = rt_vbus_chn_devx; + i < ARRAY_SIZE(_devx) && p->req.name; + i++, p++) + { + _devx[i].type = RT_Device_Class_Char; + _devx[i].open = _open; + _devx[i].close = _close; + _devx[i].read = _read; + _devx[i].write = _write; + _devx[i].control = _control; + _devx[i].user_data = p; + rt_device_register(&_devx[i], p->req.name, RT_DEVICE_FLAG_RDWR); + } + + return RT_EOK; +}