Init repository
This commit is contained in:
parent
d3ecfe3498
commit
7741f01445
35 changed files with 2067 additions and 90 deletions
38
src/boot/boot2.S
Normal file
38
src/boot/boot2.S
Normal file
|
@ -0,0 +1,38 @@
|
|||
.thumb
|
||||
|
||||
.section .boot2, "ax"
|
||||
|
||||
// Disable SSI
|
||||
ldr r0, =SSI_SSIENR
|
||||
ldr r1, =0
|
||||
str r1, [r0]
|
||||
|
||||
// Set baud rate
|
||||
ldr r0, =SSI_BAUDR
|
||||
ldr r1, =4
|
||||
str r1, [r0]
|
||||
|
||||
// Enter XIP
|
||||
ldr r0, =SSI_CTRLR0
|
||||
ldr r1, =(3 << 8) | (31 << 16)
|
||||
str r1, [r0]
|
||||
|
||||
// CTRLR0
|
||||
ldr r0, =SSI_SPI_CTRLR0
|
||||
ldr r1, =(6 << 2) | (2 << 8) | (0x03 << 24)
|
||||
str r1, [r0]
|
||||
|
||||
// Enable back SSI
|
||||
ldr r0, =SSI_SSIENR
|
||||
ldr r1, =1
|
||||
str r1, [r0]
|
||||
|
||||
// Jump to crt0.S
|
||||
ldr r0, =0x10000101
|
||||
bx r0
|
||||
|
||||
.set SSI_BASE, 0x18000000
|
||||
.set SSI_CTRLR0, SSI_BASE + 0x00
|
||||
.set SSI_SSIENR, SSI_BASE + 0x08
|
||||
.set SSI_BAUDR, SSI_BASE + 0x14
|
||||
.set SSI_SPI_CTRLR0, SSI_BASE + 0xF4
|
40
src/boot/crt0.S
Normal file
40
src/boot/crt0.S
Normal file
|
@ -0,0 +1,40 @@
|
|||
.section .crt0, "ax"
|
||||
|
||||
// Load data segment to SRAM
|
||||
ldr r0, =__data_src__
|
||||
ldr r1, =__data_dst__
|
||||
ldr r2, =__data_size__
|
||||
mov r3, #0
|
||||
data_seg_start:
|
||||
cmp r2, #0
|
||||
beq data_seg_end
|
||||
ldrb r3, [r0]
|
||||
strb r3, [r1]
|
||||
add r0, #1
|
||||
add r1, #1
|
||||
sub r2, #1
|
||||
b data_seg_start
|
||||
data_seg_end:
|
||||
|
||||
// Init bss in SRAM
|
||||
ldr r0, =__bss_start__
|
||||
ldr r1, =__bss_size__
|
||||
mov r2, #0
|
||||
bss_init_start:
|
||||
cmp r1, #0
|
||||
beq bss_init_end
|
||||
strb r2, [r0]
|
||||
add r0, #1
|
||||
sub r1, #1
|
||||
b bss_init_start
|
||||
bss_init_end:
|
||||
|
||||
// Setup stack
|
||||
ldr r0, =SRAM_END
|
||||
mov sp, r0
|
||||
|
||||
// Start kernel
|
||||
ldr r0, =main
|
||||
blx r0
|
||||
|
||||
.set SRAM_END, 0x20042000
|
87
src/libs/addrmap.h
Normal file
87
src/libs/addrmap.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
#ifndef __ADDRMAP__
|
||||
#define __ADDRMAP__
|
||||
|
||||
// ----- SIO -----
|
||||
#define SIO_BASE 0xd0000000
|
||||
#define SIO_CPUID SIO_BASE + 0x000
|
||||
#define SIO_GPIO_OE SIO_BASE + 0x020
|
||||
#define SIO_GPIO_OUT_XOR SIO_BASE + 0x01c
|
||||
#define SIO_SPINLOCK0 SIO_BASE + 0x100
|
||||
#define SIO_SPINLOCK31 SIO_BASE + 0x17c
|
||||
|
||||
// ----- RESET -----
|
||||
#define RESETS_BASE 0x4000c000
|
||||
#define RESETS_RESET RESETS_BASE + 0x0
|
||||
#define RESETS_DONE RESETS_BASE + 0x8
|
||||
|
||||
// ----- Cortex M0+ -----
|
||||
#define PPB_BASE 0xe0000000 // M0PLUS CPU registers
|
||||
#define PPB_SYST_CSR PPB_BASE + 0xe010
|
||||
#define PPB_SYST_RVR PPB_BASE + 0xe014
|
||||
#define PPB_SYST_CVR PPB_BASE + 0xe018
|
||||
#define PPB_SYST_CALIB PPB_BASE + 0xe01c
|
||||
#define PPB_NVIC_ISER PPB_BASE + 0xe100
|
||||
#define PPB_NVIC_ISPR PPB_BASE + 0xe200
|
||||
#define PPB_NVIC_ICPR PPB_BASE + 0xe280
|
||||
#define PPB_VTOR PPB_BASE + 0xed08
|
||||
|
||||
// ----- APB Peripherals -----
|
||||
// IO_BANK0
|
||||
#define IO_BANK0_BASE 0x40014000
|
||||
#define IO_BANK0_GPIO25_STATUS IO_BANK0_BASE + 0x0C8
|
||||
#define IO_BANK0_GPIO25_CTRL IO_BANK0_BASE + 0x0CC
|
||||
// CLOCKS
|
||||
#define CLOCKS_BASE 0x40008000
|
||||
#define CLOCKS_SYS_CTRL CLOCKS_BASE + 0x03c
|
||||
#define CLOCKS_SYS_DIV CLOCKS_BASE + 0x040
|
||||
#define CLOCKS_SYS_SELECTED CLOCKS_BASE + 0x044
|
||||
#define CLOCKS_REF_CTRL CLOCKS_BASE + 0x030
|
||||
#define CLOCKS_PERI_CTRL CLOCKS_BASE + 0x048
|
||||
#define CLOCKS_USB_CTRL CLOCKS_BASE + 0x054
|
||||
// XOSC
|
||||
#define XOSC_BASE 0x40024000
|
||||
#define XOSC_CTRL XOSC_BASE + 0x000
|
||||
#define XOSC_STATUS XOSC_BASE + 0x004
|
||||
#define XOSC_DORMANT XOSC_BASE + 0x008
|
||||
#define XOSC_STARTUP XOSC_BASE + 0x00c
|
||||
#define XOSC_COUNT XOSC_BASE + 0x01c
|
||||
// PLL_SYS
|
||||
#define PLL_SYS_BASE 0x40028000
|
||||
#define PLL_SYS_CS PLL_SYS_BASE + 0x000
|
||||
#define PLL_SYS_PWR PLL_SYS_BASE + 0x004
|
||||
#define PLL_SYS_FBDIV_INT PLL_SYS_BASE + 0x008
|
||||
#define PLL_SYS_PRIM PLL_SYS_BASE + 0x00c
|
||||
// PLL_USB
|
||||
#define PLL_USB_BASE 0x4002c000
|
||||
#define PLL_USB_CS PLL_USB_BASE + 0x000
|
||||
#define PLL_USB_PWR PLL_USB_BASE + 0x004
|
||||
#define PLL_USB_FBDIV_INT PLL_USB_BASE + 0x008
|
||||
#define PLL_USB_PRIM PLL_USB_BASE + 0x00c
|
||||
// SRAM
|
||||
#define SRAM_BASE 0x20000000
|
||||
#define SRAM_BANK4_BASE 0x20040000
|
||||
#define SRAM_BANK5_BASE 0x20041000
|
||||
#define SRAM_END SRAM_BASE + 0x42000
|
||||
// USB Controller
|
||||
#define USBCTRL_BASE 0x50100000
|
||||
#define USBCTRL_DPSRAM_BASE USBCTRL_BASE + 0x000
|
||||
#define USBCTRL_DPSRAM_SETUP_PACKET USBCTRL_DPSRAM_BASE + 0x000
|
||||
#define USBCTRL_REGS_BASE 0x50110000
|
||||
#define USBCTRL_EP0_BUFFER0 USBCTRL_DPSRAM_BASE + 0x100
|
||||
#define USBCTRL_EP0_BUFFER_CTRL_IN USBCTRL_DPSRAM_BASE + 0x080
|
||||
#define USBCTRL_EP0_BUFFER_CTRL_OUT USBCTRL_DPSRAM_BASE + 0x084
|
||||
#define USBCTRL_EP1_ENDP_CTRL_IN USBCTRL_DPSRAM_BASE + 0x08
|
||||
#define USBCTRL_EP1_BUFFER_CTRL_IN USBCTRL_DPSRAM_BASE + 0x88
|
||||
#define USBCTRL_DATA_BUFFER_START USBCTRL_DPSRAM_BASE + 0x180
|
||||
#define USBCTRL_ADDR_ENDP USBCTRL_REGS_BASE + 0x000
|
||||
#define USBCTRL_MAINCTRL USBCTRL_REGS_BASE + 0x040
|
||||
#define USBCTRL_SIE_CTRL USBCTRL_REGS_BASE + 0x04c
|
||||
#define USBCTRL_SIE_STATUS USBCTRL_REGS_BASE + 0x050
|
||||
#define USBCTRL_BUFF_STATUS USBCTRL_REGS_BASE + 0x058
|
||||
#define USBCTRL_INTR USBCTRL_REGS_BASE + 0x08c
|
||||
#define USBCTRL_INTE USBCTRL_REGS_BASE + 0x090
|
||||
#define USBCTRL_INTS USBCTRL_REGS_BASE + 0x098
|
||||
#define USBCTRL_MUXING USBCTRL_REGS_BASE + 0x074
|
||||
#define USBCTRL_PWR USBCTRL_REGS_BASE + 0x078
|
||||
|
||||
#endif
|
42
src/libs/bitmap.h
Normal file
42
src/libs/bitmap.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef __BITMAP_H__
|
||||
#define __BITMAP_H__
|
||||
|
||||
#define _BIT(BIT) (1u << (BIT))
|
||||
|
||||
// ----- USB Controller -----
|
||||
// INTS
|
||||
#define BIT_USBCTRL_INTS_SETUP_REQ _BIT(16)
|
||||
#define BIT_USBCTRL_INTS_BUFFER_STATUS _BIT(4)
|
||||
#define BIT_USBCTRL_INTS_TRANS_COMPLETE _BIT(3)
|
||||
#define BIT_USBCTRL_INTS_BUS_RESET _BIT(12)
|
||||
// SIE_STATUS
|
||||
#define BIT_USBCTRL_SIE_STATUS_SETUP_REC _BIT(17)
|
||||
#define BIT_USBCTRL_SIE_STATUS_BUS_RESET _BIT(19)
|
||||
// Buffer control
|
||||
#define BIT_USBCTRL_BUFFER0_PID _BIT(13)
|
||||
#define BIT_USBCTRL_BUFFER0_FULL _BIT(15)
|
||||
#define BIT_USBCTRL_BUFFER0_AVAILABLE _BIT(10)
|
||||
#define MASK_USBCTRL_BUFFER0_LENGTH (0x3ff)
|
||||
// Muxing
|
||||
#define BIT_USBCTRL_MUXING_TO_PHY _BIT(0)
|
||||
#define BIT_USBCTRL_MUXING_SOFTCON _BIT(3)
|
||||
// Power
|
||||
#define BIT_USBCTRL_PWR_VBUS_DETECT _BIT(2)
|
||||
#define BIT_USBCTRL_PWR_VBUS_DETECT_OVERRIDE_EN _BIT(3)
|
||||
// SIE_CTRL
|
||||
#define BIT_USBCTRL_SIE_CTRL_PULLUP_EN _BIT(16)
|
||||
#define BIT_USBCTRL_SIE_CTRL_PULLDOWN_EN _BIT(15)
|
||||
#define BIT_USBCTRL_SIE_CTRL_EP0_INT_1BUF _BIT(29)
|
||||
// MAIN_CTRL
|
||||
#define BIT_USBCTRL_MAIN_CTRL_CONTROLLER_EN _BIT(0)
|
||||
#define BIT_USBCTRL_MAIN_CTRL_HOST_NDEVICE _BIT(1)
|
||||
// INTE
|
||||
#define BIT_USBCTRL_INTE_SETUP_REQ _BIT(16)
|
||||
#define BIT_USBCTRL_INTE_BUS_RESET _BIT(12)
|
||||
#define BIT_USBCTRL_INTE_BUFF_STATUS _BIT(4)
|
||||
// Endpoint Control
|
||||
#define BIT_USBCTRL_ENDP_CTRL_ENABLE _BIT(31)
|
||||
#define BIT_USBCTRL_ENDP_CTRL_INT_PER_BUFF1 _BIT(29)
|
||||
#define BIT_USBCTRL_ENDP_CTRL_TYPE_LSB (26)
|
||||
|
||||
#endif
|
57
src/libs/clock.c
Normal file
57
src/libs/clock.c
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "clock.h"
|
||||
#include "addrmap.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
// Updated at each systick interrupts, one for each core
|
||||
__attribute__((aligned(4))) u32 cores_systick[2];
|
||||
|
||||
void wait(u32 ms){
|
||||
u32 cpuid=REG_READ(SIO_CPUID);
|
||||
cores_systick[cpuid]=0; // Init core counter
|
||||
while(cores_systick[cpuid]<ms){} // Wait for correct amount of ticks
|
||||
}
|
||||
|
||||
|
||||
void xosc_init() {
|
||||
// Starting xosc
|
||||
REG_WRITE(XOSC_CTRL, 0xAA0); // Straight up from doc (to set it up to max (15MHz) => 12MHz in reality because of the xosc crystal)
|
||||
REG_WRITE(XOSC_STARTUP, 0x00C4); // Startup delay (default value)
|
||||
REG_WRITE_BITMAP_SET(XOSC_CTRL, 0xFAB << 12); // Enable clock
|
||||
while(!(REG_READ(XOSC_STATUS) & 1<<31)){} // Wait for xosc to be stable
|
||||
|
||||
// Reset System PLL
|
||||
REG_WRITE_BITMAP_CLEAR(RESETS_RESET, 1<<12); // Reset System PLL
|
||||
while((REG_READ(RESETS_DONE) & 1<<12) == 0){} // Wait for System PLL reset to be done
|
||||
|
||||
// Setup and starts System PLL
|
||||
// We use default config from (P232) which generate a 125MHz clock signal
|
||||
REG_WRITE(PLL_SYS_FBDIV_INT, 125); // Multiply factor (we multply input frequency by 125 (so Fxosc * 10 = 125*12MHz = 1500MHz))
|
||||
REG_WRITE(PLL_SYS_PRIM, 6<<16|2<<12); // Post divider divide output frequency by 6 then 2 (totally 12) thus Ffinal=1500MHz/12 = 125MHz
|
||||
REG_WRITE_BITMAP_CLEAR(PLL_SYS_PWR, 1<<5|1<<3|1<<0); // Turn on VCO + PLL + fbdiv
|
||||
while(!(REG_READ(PLL_SYS_CS) & 1<<31)){} // Wait for System PLL to be locked (Fin == Fout * Fact)
|
||||
|
||||
// By default System PLL is connected to sys_clk auxsrc
|
||||
// So, just permute sys_clck to auxsrc (remember it is glitchless)
|
||||
REG_WRITE(CLOCKS_SYS_CTRL, 0x1); // Now cores are using System PLL output
|
||||
|
||||
// Setup clock interrupt (1 every ms)
|
||||
REG_WRITE(PPB_SYST_RVR, 125*1000); // We want 1tick per ms = 125MHz/125e3 = 1000Hz == 1 tick per ms, we can argue on accuracy here...
|
||||
REG_WRITE(PPB_SYST_CSR, 0b111); // Clock source for Systick is core clock (PLL)/ Interrupt enable / Counter enable
|
||||
|
||||
// Now, setup USB PLL, reset USB PLL
|
||||
REG_WRITE_BITMAP_CLEAR(RESETS_RESET, 1<<13); // Reset USB PLL
|
||||
while((REG_READ(RESETS_DONE) & 1<<13) == 0){} // Wait for USB PLL reset to be done
|
||||
|
||||
// We use default config from (P232) which generate a 48MHz clock signal for USB
|
||||
REG_WRITE(PLL_USB_FBDIV_INT, 100); // Multiply factor (we multply input frequency by 100 (so Fxosc * 100 = 100*12MHz = 1200MHz))
|
||||
REG_WRITE(PLL_USB_PRIM, 5<<16|5<<12); // Post divider divide output frequency by 5 then 5 (totally 25) thus Ffinal=1200MHz/25 = 48MHz
|
||||
REG_WRITE_BITMAP_CLEAR(PLL_USB_PWR, 1<<5|1<<3|1<<0); // Turn on VCO + PLL + fbdiv
|
||||
while(!(REG_READ(PLL_USB_CS) & 1<<31)){} // Wait for USB PLL to be locked
|
||||
|
||||
// Enable USB clock generator
|
||||
REG_WRITE(CLOCKS_USB_CTRL,1<<11);
|
||||
|
||||
// Last step, use XOSC for clock ref
|
||||
REG_WRITE(CLOCKS_REF_CTRL, 2); // This is glitchless
|
||||
}
|
9
src/libs/clock.h
Normal file
9
src/libs/clock.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef __CLOCK_H__
|
||||
#define __CLOCK_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void xosc_init();
|
||||
void wait(u32 ms); // Did not test much that one
|
||||
|
||||
#endif
|
39
src/libs/gpio.c
Normal file
39
src/libs/gpio.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "addrmap.h"
|
||||
#include "utils.h"
|
||||
#include "gpio.h"
|
||||
|
||||
void gpio_init() { REG_WRITE_BITMAP_CLEAR(RESETS_BASE, 32);} // Reset bank0 (all gpios)
|
||||
|
||||
void gpio_set_function(u8 gpio, u8 fn){
|
||||
REG_WRITE(IO_BANK0_GPIO25_CTRL, fn); // Set function as SIO
|
||||
}
|
||||
|
||||
void gpio_output_enable(u8 gpio){
|
||||
u32 r=REG_READ(SIO_GPIO_OE)|1<<gpio;
|
||||
REG_WRITE(SIO_GPIO_OE, r);
|
||||
}
|
||||
|
||||
void gpio_toggle_state(u8 gpio){
|
||||
REG_WRITE(SIO_GPIO_OUT_XOR,1<<gpio);
|
||||
}
|
||||
|
||||
void gpio_toggle_led(){
|
||||
// Ensure led pin is configured
|
||||
u32 fn=REG_READ(IO_BANK0_GPIO25_CTRL);
|
||||
u32 oe=REG_READ(SIO_GPIO_OE)&1<<25;
|
||||
if(fn!=GPIO_FN_SIO || !oe){
|
||||
gpio_set_function(25, GPIO_FN_SIO);
|
||||
gpio_output_enable(25);
|
||||
}
|
||||
gpio_toggle_state(25); // Switch between ON/OFF
|
||||
}
|
||||
|
||||
|
||||
void gpio_blink_led(int n){
|
||||
for(int i=0;i<n;i++){
|
||||
gpio_toggle_led();
|
||||
for(int j=0;j<5000000;j++){} // These are disgusting but I am lazy..
|
||||
gpio_toggle_led();
|
||||
for(int j=0;j<5000000;j++){}
|
||||
}
|
||||
}
|
22
src/libs/gpio.h
Normal file
22
src/libs/gpio.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef __GPIO_H__
|
||||
#define __GPIO_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define GPIO_FN_SPI 1
|
||||
#define GPIO_FN_UART 2
|
||||
#define GPIO_FN_I2C 3
|
||||
#define GPIO_FN_PWM 4
|
||||
#define GPIO_FN_SIO 5
|
||||
#define GPIO_FN_PIO0 6
|
||||
#define GPIO_FN_PIO1 7
|
||||
#define GPIO_FN_USB 8
|
||||
|
||||
void gpio_init();
|
||||
void gpio_set_function(u8 gpio, u8 fn);
|
||||
void gpio_output_enable(u8 gpio);
|
||||
void gpio_toggle_state(u8 gpio);
|
||||
void gpio_toggle_led();
|
||||
void gpio_blink_led(int n);
|
||||
|
||||
#endif
|
67
src/libs/interrupts.c
Normal file
67
src/libs/interrupts.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "interrupts.h"
|
||||
#include "addrmap.h"
|
||||
#include "bitmap.h"
|
||||
#include "utils.h"
|
||||
#include "gpio.h"
|
||||
#include "usb/cusb.h"
|
||||
|
||||
extern u32 cores_systick[];
|
||||
|
||||
void isr_unbind(void){}
|
||||
|
||||
void isr_systick(void){
|
||||
cores_systick[0]++; // Core 0
|
||||
cores_systick[1]++; // Core 1
|
||||
}
|
||||
|
||||
void isr_usb(){
|
||||
if(cusb_check_interrupt(BIT_USBCTRL_INTS_SETUP_REQ)){
|
||||
REG_WRITE_BITMAP_CLEAR(USBCTRL_SIE_STATUS, BIT_USBCTRL_SIE_STATUS_SETUP_REC);
|
||||
cusb_handle_setup();
|
||||
}
|
||||
if(cusb_check_interrupt(BIT_USBCTRL_INTS_BUS_RESET)){
|
||||
REG_WRITE_BITMAP_CLEAR(USBCTRL_SIE_STATUS, BIT_USBCTRL_SIE_STATUS_BUS_RESET);
|
||||
cusb_handle_bus_reset();
|
||||
}
|
||||
if(cusb_check_interrupt(BIT_USBCTRL_INTS_BUFFER_STATUS)){
|
||||
cusb_handle_buffer_status();
|
||||
}
|
||||
cusb_eoi();
|
||||
}
|
||||
|
||||
__attribute__((used,aligned(4),section(".vector_table"))) void (*vtable[])(void) = {
|
||||
(void (*)(void))SRAM_END,
|
||||
// ----- Start of internal (to core) interrupts
|
||||
isr_unbind, // 01-NMI
|
||||
isr_unbind, // 02-HardFault
|
||||
isr_unbind, // 03-Unused
|
||||
isr_unbind, // 04-Unused
|
||||
isr_unbind, // 05-Unused
|
||||
isr_unbind, // 06-Unused
|
||||
isr_unbind, // 07-Unused
|
||||
isr_unbind, // 08-Unused
|
||||
isr_unbind, // 09-Unused
|
||||
isr_unbind, // 10-Unused
|
||||
isr_unbind, // 11-SVCall
|
||||
isr_unbind, // 12-Unused
|
||||
isr_unbind, // 13-Unused
|
||||
isr_unbind, // 14-PendSV
|
||||
isr_systick, // 15-SysTick
|
||||
// ----- Start of external (RP2040 ones) interrupts
|
||||
isr_unbind, // 00-Unused
|
||||
isr_unbind, // 01-Unused
|
||||
isr_unbind, // 02-Unused
|
||||
isr_unbind, // 03-Unused
|
||||
isr_unbind, // 04-Unused
|
||||
isr_usb // 05-Usb Controller
|
||||
};
|
||||
|
||||
void interrupts_init(){
|
||||
memcpy((void*)SRAM_BASE, (void*)vtable, 4*30);
|
||||
REG_WRITE(PPB_VTOR, SRAM_BASE);
|
||||
}
|
||||
|
||||
void interrupts_enable(int num){
|
||||
REG_WRITE(PPB_NVIC_ICPR, 1<<num); // Clear pending interrupts
|
||||
REG_WRITE(PPB_NVIC_ISER, 1<<num); // Enable num interrupts
|
||||
}
|
7
src/libs/interrupts.h
Normal file
7
src/libs/interrupts.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef __INTERRUPT_H__
|
||||
#define __INTERRUPT_H__
|
||||
|
||||
void interrupts_init();
|
||||
void interrupts_enable(int num);
|
||||
|
||||
#endif
|
25
src/libs/lock.c
Normal file
25
src/libs/lock.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "lock.h"
|
||||
#include "utils.h"
|
||||
#include "addrmap.h"
|
||||
#include "time.h"
|
||||
|
||||
char locks_pool[LOCKS_POOL_SIZE]; // Automatically zeroed (.bss)
|
||||
|
||||
void lock_acquire(int lockid) {
|
||||
while(1){
|
||||
while(locks_pool[lockid]) {} // Lurking stage
|
||||
while(!REG_READ(HARDWARE_LOCK)){} // Acquire HW lock
|
||||
if(!locks_pool[lockid]){
|
||||
locks_pool[lockid]=1; // Acquire the lock
|
||||
REG_WRITE(HARDWARE_LOCK,0); // Release HW lock
|
||||
break;
|
||||
}
|
||||
REG_WRITE(HARDWARE_LOCK,0);
|
||||
}
|
||||
}
|
||||
|
||||
void lock_release(int lockid) {
|
||||
while(!REG_READ(HARDWARE_LOCK)){}
|
||||
locks_pool[lockid]=0;
|
||||
REG_WRITE(HARDWARE_LOCK,0);
|
||||
}
|
10
src/libs/lock.h
Normal file
10
src/libs/lock.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef __LOCK_H__
|
||||
#define __LOCK_H__
|
||||
|
||||
#define LOCKS_POOL_SIZE 10
|
||||
#define HARDWARE_LOCK SIO_SPINLOCK31
|
||||
|
||||
void lock_acquire(int lockid);
|
||||
void lock_release(int lockid);
|
||||
|
||||
#endif
|
27
src/libs/tty.c
Normal file
27
src/libs/tty.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include "tty.h"
|
||||
#include "gpio.h"
|
||||
#include "usb/cdc-acm.h"
|
||||
#include "usb/cusb.h"
|
||||
#include "utils.h"
|
||||
#include "addrmap.h"
|
||||
|
||||
|
||||
void tty_init(void){
|
||||
usb_cdc_acm_init();
|
||||
}
|
||||
|
||||
char tty_getchar(void){
|
||||
char c;
|
||||
usb_cdc_acm_recv(&c, 1);
|
||||
return c;
|
||||
}
|
||||
|
||||
void tty_putchar(char c){
|
||||
char str[2]="";
|
||||
str[0]=c;
|
||||
usb_cdc_acm_send(str, 2);
|
||||
}
|
||||
|
||||
void tty_putstr(char *str){
|
||||
usb_cdc_acm_send(str, strlen(str)+1);
|
||||
}
|
9
src/libs/tty.h
Normal file
9
src/libs/tty.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef __TTY_H__
|
||||
#define __TTY_H__
|
||||
|
||||
void tty_init(void);
|
||||
char tty_getchar(void);
|
||||
void tty_putchar(char c);
|
||||
void tty_putstr(char *str);
|
||||
|
||||
#endif
|
8
src/libs/types.h
Normal file
8
src/libs/types.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef __TYPES_H__
|
||||
#define __TYPES_H__
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
#endif
|
184
src/libs/usb/cdc-acm.c
Normal file
184
src/libs/usb/cdc-acm.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include "cdc-acm.h"
|
||||
#include "cusb.h"
|
||||
#include "proto.h"
|
||||
#include "../gpio.h"
|
||||
#include "../addrmap.h"
|
||||
|
||||
void cdc_acm_ep1_in_handler(u8 *buffer, int len);
|
||||
void cdc_acm_ep2_in_handler(u8 *buffer, int len);
|
||||
void cdc_acm_ep3_out_handler(u8 *buffer, int len);
|
||||
void cdc_acm_setup_handler(UD_SETUP *pkt);
|
||||
void cdc_acm_setup_ack_handler(void);
|
||||
void cdc_acm_eoi(void);
|
||||
|
||||
u8 configuration_descriptor[128];
|
||||
u8 *send_buffer;
|
||||
u8 send_buffer_size=0;
|
||||
u8 *recv_buffer;
|
||||
u8 recv_buffer_size=0;
|
||||
|
||||
DeviceConfiguration CDC_ACM_CONFIG ={
|
||||
.device_descriptor = {
|
||||
.bDeviceClass = USB_DEVICE_CLASS_CDC,
|
||||
.idProduct = 1,
|
||||
.iManufacturer = 1, // String id 1
|
||||
.iProduct = 2 // String id 2
|
||||
},
|
||||
.configuration_descriptor = {
|
||||
.bNumInterfaces = 2
|
||||
},
|
||||
.interface_descriptors = {
|
||||
{
|
||||
.bInterfaceClass = USB_INTERFACE_CLASS_COMMUNICATION,
|
||||
.bInterfaceSubClass = USB_INTERFACE_SUBCLASS_ACM,
|
||||
.bInterfaceProtocol = USB_INTERFACE_COMMUNICATION_PROTOCOL_NOPROTO,
|
||||
.bInterfaceNumber = 0,
|
||||
.bNumEndpoints = 1 // SHOULD BE 1 (IT IS 0 BECAUSE GET_CONFIG DESCRIPTOR MUST BE UPDATED)
|
||||
},
|
||||
{
|
||||
.bInterfaceClass = USB_INTERFACE_CLASS_DATA,
|
||||
.bInterfaceProtocol = USB_INTERFACE_COMMUNICATION_PROTOCOL_NOPROTO,
|
||||
.bInterfaceNumber = 1,
|
||||
.bNumEndpoints = 2
|
||||
}
|
||||
},
|
||||
.endpoints = {
|
||||
{
|
||||
.endpoint_descriptor = {
|
||||
.bEndpointAddress = B_ENDPOINT_ADDRESS(1, USB_DIRECTION_IN),
|
||||
.wMaxPacketSize=64,
|
||||
.bmAttributes = USB_TRANSFERT_TYPE_INTERRUPT,
|
||||
.bInterval = 0
|
||||
},
|
||||
.handler = cdc_acm_ep1_in_handler
|
||||
},
|
||||
{
|
||||
.endpoint_descriptor = {
|
||||
.bEndpointAddress = B_ENDPOINT_ADDRESS(2, USB_DIRECTION_IN),
|
||||
.wMaxPacketSize=64,
|
||||
.bmAttributes = USB_TRANSFERT_TYPE_BULK,
|
||||
.bInterval = 0
|
||||
},
|
||||
.handler = cdc_acm_ep2_in_handler
|
||||
},
|
||||
{
|
||||
.endpoint_descriptor = {
|
||||
.bEndpointAddress = B_ENDPOINT_ADDRESS(3, USB_DIRECTION_OUT),
|
||||
.wMaxPacketSize=64,
|
||||
.bmAttributes = USB_TRANSFERT_TYPE_BULK,
|
||||
.bInterval = 0
|
||||
},
|
||||
.handler = cdc_acm_ep3_out_handler
|
||||
},
|
||||
},
|
||||
.descriptor_strings = {
|
||||
"Raspberry Pi", // Vendor
|
||||
"Pico RP2040" // Product
|
||||
},
|
||||
.supported_languages = {
|
||||
.wLANGID0 = USB_LANG_ENGLISH_US
|
||||
},
|
||||
.setup_handler = cdc_acm_setup_handler,
|
||||
.setup_ack_handler = cdc_acm_setup_ack_handler,
|
||||
.eoi=cdc_acm_eoi
|
||||
};
|
||||
|
||||
|
||||
void usb_cdc_acm_init(void) {
|
||||
cusb_init(&CDC_ACM_CONFIG);
|
||||
USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR f;
|
||||
f.header_descriptor.bFunctionLength=sizeof(USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR);
|
||||
f.header_descriptor.bDescriptorType=0x24;
|
||||
f.header_descriptor.bcdCDC=0b0110;
|
||||
f.acm_descriptor.bFunctionLength=sizeof(USB_ACM_FUNCTIONAL_DESCRIPTOR);
|
||||
f.acm_descriptor.bDescriptorType=0x24;
|
||||
f.acm_descriptor.bDescriptorSubtype=0x02;
|
||||
f.acm_descriptor.bmCapabilities=0xf;
|
||||
f.union_descriptor.bFunctionLength=sizeof(USB_UNION_INTERFACE_DESCRIPTOR);
|
||||
f.union_descriptor.bDescriptorType=0x24;
|
||||
f.union_descriptor.bDescriptorSubtype=0x06;
|
||||
f.union_descriptor.bMasterInterface=0;
|
||||
f.union_descriptor.bSlaveInterface0=1;
|
||||
|
||||
// ----- Setting-up full configuration descriptor -----
|
||||
u8 *ptr=configuration_descriptor;
|
||||
// Configuration descriptor
|
||||
memcpy(ptr,(void*) &(CDC_ACM_CONFIG.configuration_descriptor), sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
||||
ptr+=sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
||||
// Communication interface descriptor
|
||||
memcpy(ptr,(void*) &(CDC_ACM_CONFIG.interface_descriptors[0]), sizeof(USB_INTERFACE_DESCRIPTOR));
|
||||
ptr+=sizeof(USB_INTERFACE_DESCRIPTOR);
|
||||
memcpy(ptr,(void*) &f, sizeof(USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR)); // Functional descriptor
|
||||
ptr+=sizeof(USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR);
|
||||
memcpy(ptr,(void*) &(CDC_ACM_CONFIG.endpoints[0].endpoint_descriptor), sizeof(USB_ENDPOINT_DESCRIPTOR)); // Endpoint descriptor
|
||||
ptr+=sizeof(USB_ENDPOINT_DESCRIPTOR);
|
||||
|
||||
// Data interface descriptor
|
||||
memcpy(ptr,(void*) &(CDC_ACM_CONFIG.interface_descriptors[1]), sizeof(USB_INTERFACE_DESCRIPTOR));
|
||||
ptr+=sizeof(USB_INTERFACE_DESCRIPTOR);
|
||||
memcpy(ptr,(void*) &(CDC_ACM_CONFIG.endpoints[1].endpoint_descriptor), sizeof(USB_ENDPOINT_DESCRIPTOR));
|
||||
ptr+=sizeof(USB_ENDPOINT_DESCRIPTOR);
|
||||
memcpy(ptr,(void*) &(CDC_ACM_CONFIG.endpoints[2].endpoint_descriptor), sizeof(USB_ENDPOINT_DESCRIPTOR));
|
||||
ptr+=sizeof(USB_ENDPOINT_DESCRIPTOR);
|
||||
|
||||
// Setup full descriptor length
|
||||
USB_CONFIGURATION_DESCRIPTOR *conf=(USB_CONFIGURATION_DESCRIPTOR*)configuration_descriptor;
|
||||
conf->wTotalLength=ptr-configuration_descriptor;
|
||||
|
||||
// Finalize
|
||||
CDC_ACM_CONFIG.full_configuration_descriptor=configuration_descriptor;
|
||||
|
||||
// Start receiving from host
|
||||
cusb_start_xfer(0,64,&(CDC_ACM_CONFIG.endpoints[2]));
|
||||
}
|
||||
|
||||
void cdc_acm_ep1_in_handler(u8 *buffer, int len) {}
|
||||
|
||||
void cdc_acm_ep2_in_handler(u8 *buffer, int len) {
|
||||
send_buffer_size=0;
|
||||
}
|
||||
|
||||
void cdc_acm_ep3_out_handler(u8 *buffer, int len) {
|
||||
if(recv_buffer_size){
|
||||
memcpy(recv_buffer, buffer, len);
|
||||
recv_buffer_size=0; // Prevent further receive until usb_cdc_acm_recv() is called again
|
||||
cusb_start_xfer(0,64,&(CDC_ACM_CONFIG.endpoints[2]));
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_acm_setup_handler(UD_SETUP *pkt){
|
||||
u8 direction=pkt->bmRequestType & BM_REQUEST_TYPE_DIR_BIT;
|
||||
if(pkt->bRequest == USB_REQUEST_CODE_SET_LINE_CODING){
|
||||
// TODO
|
||||
}
|
||||
else if(pkt->bRequest == USB_REQUEST_CODE_SET_CONTROL_LINE_STATE){
|
||||
// TODO
|
||||
}
|
||||
else if(pkt->bRequest == USB_REQUEST_CODE_SEND_BREAK){
|
||||
// TODO
|
||||
}
|
||||
else {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
||||
void cdc_acm_setup_ack_handler(void){
|
||||
}
|
||||
|
||||
void cdc_acm_eoi(void){
|
||||
if(send_buffer_size)
|
||||
cusb_start_xfer(send_buffer,send_buffer_size,&(CDC_ACM_CONFIG.endpoints[1]));
|
||||
}
|
||||
|
||||
void usb_cdc_acm_send(char *data, int size){
|
||||
send_buffer=data;
|
||||
send_buffer_size=size;
|
||||
cusb_isr_trigger();
|
||||
while(send_buffer_size){};
|
||||
}
|
||||
|
||||
void usb_cdc_acm_recv(char *data, int size){
|
||||
recv_buffer=data;
|
||||
recv_buffer_size=size;
|
||||
while(recv_buffer_size){}
|
||||
}
|
10
src/libs/usb/cdc-acm.h
Normal file
10
src/libs/usb/cdc-acm.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef __CDC_ACM_H__
|
||||
#define __CDC_ACM_H__
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
void usb_cdc_acm_init(void);
|
||||
void usb_cdc_acm_send(char *data, int size);
|
||||
void usb_cdc_acm_recv(char *data, int size);
|
||||
|
||||
#endif
|
309
src/libs/usb/cusb.c
Normal file
309
src/libs/usb/cusb.c
Normal file
|
@ -0,0 +1,309 @@
|
|||
#include "cusb.h"
|
||||
#include "../addrmap.h"
|
||||
#include "../bitmap.h"
|
||||
#include "../interrupts.h"
|
||||
#include "../gpio.h"
|
||||
#include "proto.h"
|
||||
|
||||
u8 xferbuff[64]; // Free to use for transfer (IN)
|
||||
u8 *xferptr;
|
||||
u8 xferremain=0;
|
||||
DeviceConfiguration *cusb_dc;
|
||||
|
||||
void cusb_init(DeviceConfiguration *dc){
|
||||
|
||||
// Reset USB controller
|
||||
REG_WRITE_BITMAP_CLEAR(RESETS_RESET, 1<<24); // Reset USBCTRL
|
||||
while((REG_READ(RESETS_DONE) & 1<<24) == 0){} // Wait controller reset
|
||||
|
||||
// Flush USB Controller DPSRAM
|
||||
memset((void*)USBCTRL_DPSRAM_BASE, 0, USBCTRL_DPSRAM_SIZE);
|
||||
|
||||
// Enable usb controller interrupt
|
||||
interrupts_enable(5);
|
||||
|
||||
// Setup controller
|
||||
REG_WRITE(USBCTRL_MUXING, BIT_USBCTRL_MUXING_TO_PHY|BIT_USBCTRL_MUXING_SOFTCON);
|
||||
REG_WRITE(USBCTRL_PWR, BIT_USBCTRL_PWR_VBUS_DETECT|BIT_USBCTRL_PWR_VBUS_DETECT_OVERRIDE_EN);
|
||||
REG_WRITE(USBCTRL_MAINCTRL, BIT_USBCTRL_MAIN_CTRL_CONTROLLER_EN); // Set device mode + enable controller
|
||||
REG_WRITE(USBCTRL_SIE_CTRL, BIT_USBCTRL_SIE_CTRL_EP0_INT_1BUF); // Enable usb interrupts on EP0
|
||||
REG_WRITE(USBCTRL_INTE, BIT_USBCTRL_INTE_SETUP_REQ|BIT_USBCTRL_INTE_BUS_RESET|BIT_USBCTRL_INTE_BUFF_STATUS); // Setup interrupt granularity
|
||||
|
||||
// Initialize device configuration
|
||||
cusb_dc=dc; // Store controller device config
|
||||
cusb_init_device_configuration();
|
||||
|
||||
// Initialize endpoints
|
||||
for(int i=0;i<USB_ENDPOINT_COUNT;i++){
|
||||
EndPointConfiguration *ep=&(cusb_dc->endpoints[i]);
|
||||
u32 dir=ep->endpoint_descriptor.bEndpointAddress & 0x80;
|
||||
u32 id=ep->endpoint_descriptor.bEndpointAddress & 0xF;
|
||||
// Endpoint and buffer control
|
||||
u32 endpoint_control=USBCTRL_EP1_ENDP_CTRL_IN+0x8*(id-1); // -1 since start at 1 (ep0 already covered in cusb_init_device_configuration())
|
||||
u32 buffer_control=USBCTRL_EP1_BUFFER_CTRL_IN+0x8*(id-1);
|
||||
if(dir == USB_DIRECTION_OUT){
|
||||
endpoint_control+=4;
|
||||
buffer_control+=4;
|
||||
}
|
||||
ep->endpoint_control=(void*)(endpoint_control);
|
||||
ep->buffer_control=(void*)(buffer_control);
|
||||
// Init buffers
|
||||
u32 buffer0=USBCTRL_DATA_BUFFER_START+(64*2)*(id-1); // 64 bits aligned warning see p388
|
||||
u32 buffer1=buffer0+64;
|
||||
ep->buffer0=(void*)buffer0;
|
||||
ep->buffer1=(void*)buffer1;
|
||||
// Init ep control
|
||||
u32 epctrl=BIT_USBCTRL_ENDP_CTRL_ENABLE |
|
||||
BIT_USBCTRL_ENDP_CTRL_INT_PER_BUFF1 |
|
||||
ep->endpoint_descriptor.bmAttributes << BIT_USBCTRL_ENDP_CTRL_TYPE_LSB|
|
||||
USB_BUFFER_OFFSET(buffer0);
|
||||
*ep->endpoint_control=epctrl; // Apply buffer control setting
|
||||
ep->next_pid=0; // Maybe that is good?
|
||||
}
|
||||
|
||||
// Pull-up usb line! (for the host :)
|
||||
REG_WRITE_BITMAP_SET(USBCTRL_SIE_CTRL, BIT_USBCTRL_SIE_CTRL_PULLUP_EN);
|
||||
}
|
||||
|
||||
void cusb_init_device_configuration(){
|
||||
|
||||
// Init device descriptor
|
||||
cusb_dc->device_descriptor.bLength=sizeof(USB_DEVICE_DESCRIPTOR);
|
||||
cusb_dc->device_descriptor.bDescriptorType=USB_DESCRIPTOR_TYPE_DEVICE;
|
||||
cusb_dc->device_descriptor.bNumConfigurations = 1; // We support only 1
|
||||
cusb_dc->device_descriptor.bcdUSB=BCD_USB;
|
||||
cusb_dc->device_descriptor.bMaxPacketSize0=64;
|
||||
|
||||
// Init configuration descriptor
|
||||
cusb_dc->configuration_descriptor.bLength=sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
||||
cusb_dc->configuration_descriptor.bDescriptorType=USB_DESCRIPTOR_TYPE_CONFIGURATION;
|
||||
cusb_dc->configuration_descriptor.bConfigurationValue = 1; // Configuration id
|
||||
cusb_dc->configuration_descriptor.iConfiguration = 0; // No string
|
||||
cusb_dc->configuration_descriptor.bmAttributes = 0xC0; // attributes: self powered, no remote wakeup
|
||||
cusb_dc->configuration_descriptor.bMaxPower = 0x32; // 100ma
|
||||
|
||||
// Init device state
|
||||
cusb_dc->devaddr=0; // Just in case
|
||||
cusb_dc->setdevaddr=0; // Just in case
|
||||
cusb_dc->setdevaddr=0; // Just in case
|
||||
|
||||
// Init string zero descriptor
|
||||
cusb_dc->supported_languages.bLength = sizeof(USB_STRING_DESCRIPTOR_ZERO);
|
||||
cusb_dc->supported_languages.bDescriptorType = USB_DESCRIPTOR_TYPE_STRING;
|
||||
|
||||
// Init ep0 in
|
||||
EndPointConfiguration *ep0_in= &(cusb_dc->endpoints[USB_ENDPOINT_COUNT]);
|
||||
ep0_in->buffer0=(void*)USBCTRL_EP0_BUFFER0;
|
||||
ep0_in->buffer1=(void*)USBCTRL_EP0_BUFFER0+0x40;
|
||||
ep0_in->buffer_control=(void*)USBCTRL_EP0_BUFFER_CTRL_IN;
|
||||
ep0_in->handler=cusb_ep0_in_handler;
|
||||
ep0_in->endpoint_descriptor.bEndpointAddress = B_ENDPOINT_ADDRESS(0, USB_DIRECTION_IN);
|
||||
ep0_in->endpoint_descriptor.bmAttributes = USB_TRANSFERT_TYPE_CONTROL;
|
||||
ep0_in->endpoint_descriptor.wMaxPacketSize=64;
|
||||
|
||||
// Init ep0 out
|
||||
EndPointConfiguration *ep0_out= &(cusb_dc->endpoints[USB_ENDPOINT_COUNT+1]);
|
||||
ep0_out->buffer0=(void*)USBCTRL_EP0_BUFFER0;
|
||||
ep0_out->buffer1=(void*)USBCTRL_EP0_BUFFER0+0x40;
|
||||
ep0_out->buffer_control=(void*)USBCTRL_EP0_BUFFER_CTRL_OUT;
|
||||
ep0_out->handler=cusb_ep0_out_handler;
|
||||
ep0_out->endpoint_descriptor.bEndpointAddress = B_ENDPOINT_ADDRESS(0, USB_DIRECTION_OUT);
|
||||
ep0_out->endpoint_descriptor.bmAttributes = USB_TRANSFERT_TYPE_CONTROL;
|
||||
ep0_out->endpoint_descriptor.wMaxPacketSize=64;
|
||||
|
||||
// Init bLength
|
||||
for(char i=0;i<USB_ENDPOINT_COUNT+2;i++){
|
||||
cusb_dc->endpoints[i].endpoint_descriptor.bLength=sizeof(USB_ENDPOINT_DESCRIPTOR);
|
||||
cusb_dc->endpoints[i].endpoint_descriptor.bDescriptorType=USB_DESCRIPTOR_TYPE_ENDPOINT;
|
||||
}
|
||||
|
||||
// Init interfaces
|
||||
for(char i=0;i<USB_INTERFACE_COUNT;i++){
|
||||
cusb_dc->interface_descriptors[i].bLength=sizeof(USB_INTERFACE_DESCRIPTOR);
|
||||
cusb_dc->interface_descriptors[i].bDescriptorType=USB_DESCRIPTOR_TYPE_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
int cusb_check_interrupt(int int_bit){
|
||||
if(REG_READ(USBCTRL_INTS) & int_bit)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cusb_handle_bus_reset(void){
|
||||
// https://github.com/raspberrypi/pico-examples/blob/master/usb/device/dev_lowlevel/dev_lowlevel.c#L469
|
||||
REG_WRITE(USBCTRL_ADDR_ENDP, 0); // Remove device address from controller
|
||||
cusb_dc->devaddr=0; // No more device address
|
||||
cusb_dc->setdevaddr=0; // Ensure no device address will be set
|
||||
cusb_dc->configured=0;
|
||||
}
|
||||
|
||||
EndPointConfiguration* cusb_get_endpoint(char num, u32 direction){
|
||||
EndPointConfiguration *ep;
|
||||
for(char i=0;i<(USB_ENDPOINT_COUNT+2);i++){
|
||||
ep=&(cusb_dc->endpoints[i]);
|
||||
u32 bEndpointAddress=ep->endpoint_descriptor.bEndpointAddress;
|
||||
// Bit 7 (mask 0x80) is IN or OUT and first 4 bits is addr (see p269)
|
||||
if((bEndpointAddress & 0x80) == direction && (bEndpointAddress & 0xF) == num)
|
||||
return ep;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cusb_handle_setup(void){
|
||||
UD_SETUP *pkt=(UD_SETUP*)USBCTRL_DPSRAM_SETUP_PACKET;
|
||||
|
||||
// Always responds with DATA1 PID
|
||||
EndPointConfiguration *ep=cusb_get_endpoint(0, USB_DIRECTION_IN);
|
||||
ep->next_pid=1;
|
||||
|
||||
u8 direction=pkt->bmRequestType & BM_REQUEST_TYPE_DIR_BIT;
|
||||
if(direction == USB_DIRECTION_OUT){
|
||||
if (pkt->bRequest == USB_REQUEST_CODE_SET_ADDRESS){
|
||||
cusb_dc->devaddr= pkt->wValue & 0xff;
|
||||
cusb_dc->setdevaddr=1;
|
||||
// Since we should acknowledge (status phase) before setting the address
|
||||
// we use setdevaddr boolean. When status done, buffer_status interrupt will be triggered
|
||||
// and ep0_in_handler will set the address
|
||||
cusb_status_xfer(USB_DIRECTION_IN);
|
||||
} else if (pkt->bRequest == USB_REQUEST_CODE_SET_CONFIGURATION) {
|
||||
cusb_status_xfer(USB_DIRECTION_IN);
|
||||
cusb_dc->configured=1;
|
||||
} else {
|
||||
if(cusb_dc->setup_handler){
|
||||
cusb_dc->setup_handler(pkt);
|
||||
}
|
||||
// Acknowledge whatever other requests
|
||||
cusb_status_xfer(USB_DIRECTION_IN);
|
||||
}
|
||||
} else if(direction == USB_DIRECTION_IN){
|
||||
if(pkt->bRequest == USB_REQUEST_CODE_GET_DESCRIPTOR){
|
||||
int desc_type=pkt->wValue>>8; // See USB SPecification (wValue contains descriptor type+index)
|
||||
if(desc_type == USB_DESCRIPTOR_TYPE_DEVICE ){
|
||||
// Send descriptor
|
||||
cusb_start_xfer(&cusb_dc->device_descriptor, sizeof(USB_DEVICE_DESCRIPTOR), ep);
|
||||
} else if(desc_type == USB_DESCRIPTOR_TYPE_CONFIGURATION ){
|
||||
|
||||
USB_CONFIGURATION_DESCRIPTOR *conf=cusb_dc->full_configuration_descriptor;
|
||||
int size=conf->bLength;
|
||||
|
||||
if(pkt->wLength > size)
|
||||
size=conf->wTotalLength;
|
||||
|
||||
// Send descriptors!!
|
||||
cusb_start_xfer(conf, size, ep);
|
||||
} else if(desc_type == USB_DESCRIPTOR_TYPE_STRING ){
|
||||
u8 id = pkt->wValue & 0xff; // Get string id
|
||||
if(id==0){ // This is the special string descriptor for supported language
|
||||
cusb_start_xfer(&(cusb_dc->supported_languages), sizeof(USB_STRING_DESCRIPTOR_ZERO), ep);
|
||||
}
|
||||
else {
|
||||
char *str=cusb_dc->descriptor_strings[id-1]; // Remember id 0 taken by ZERO DESCriptor
|
||||
u8 *ptr=xferbuff;
|
||||
USB_UNICODE_STRING_DESCRIPTOR *u=(USB_UNICODE_STRING_DESCRIPTOR*)ptr;
|
||||
u->bLength = sizeof(USB_UNICODE_STRING_DESCRIPTOR);
|
||||
u->bDescriptorType=USB_DESCRIPTOR_TYPE_STRING;
|
||||
char c;
|
||||
ptr+=sizeof(USB_UNICODE_STRING_DESCRIPTOR); // String first 2 descriptor entries
|
||||
do {
|
||||
c = *str++;
|
||||
*ptr++ = c;
|
||||
*ptr++ = 0; // Unicode
|
||||
u->bLength+=2; // Unicode
|
||||
} while(c != '\0');
|
||||
cusb_start_xfer(xferbuff, u->bLength, ep);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cusb_dc->setup_handler(pkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cusb_handle_buffer_status(void){
|
||||
u32 status=REG_READ(USBCTRL_BUFF_STATUS);
|
||||
for(u8 num=0;num<16;num++){
|
||||
for(u8 i=0;i<2;i++){
|
||||
u32 bit=1u << (num*2+i); // Shift register for IN and OUT for endpoint num
|
||||
if(status & bit){
|
||||
u32 dir=i ? USB_DIRECTION_OUT : USB_DIRECTION_IN;
|
||||
EndPointConfiguration *ep=cusb_get_endpoint(num,dir);
|
||||
REG_WRITE_BITMAP_CLEAR(USBCTRL_BUFF_STATUS, bit); // Clear buffer status
|
||||
ep->handler((u8*)ep->buffer0,*(ep->buffer_control)&MASK_USBCTRL_BUFFER0_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cusb_status_xfer(u32 dir){
|
||||
// If dir == USB_DIRECTION_OUT
|
||||
// controller will receive the out token from host then send acknowledgement
|
||||
// otherwise if we do not perform xfer when receiving out token, then controller do not send acknowledgement which do not complete the control transaction
|
||||
// If dir == USB_DIRECTION_IN
|
||||
// controller will receive the in token from host then send zlp and receive acknowledgement from host
|
||||
EndPointConfiguration *ep=cusb_get_endpoint(0, dir);
|
||||
cusb_start_xfer(0,0,ep);
|
||||
}
|
||||
|
||||
void cusb_ep0_in_handler(u8 *buffer, int len) {
|
||||
// This function is trigger when buff_status interrupt is handled
|
||||
// it is called inside cusb_handle_buffer_status
|
||||
if(cusb_dc->setdevaddr){
|
||||
REG_WRITE(USBCTRL_ADDR_ENDP, cusb_dc->devaddr);
|
||||
cusb_dc->setdevaddr=0;
|
||||
}
|
||||
else if(xferremain>0){
|
||||
EndPointConfiguration *ep=cusb_get_endpoint(0, USB_DIRECTION_IN);
|
||||
cusb_start_xfer(xferptr,xferremain,ep);
|
||||
}
|
||||
else {
|
||||
cusb_status_xfer(USB_DIRECTION_OUT); // Acknowledge with zlp when setup transaction ends
|
||||
}
|
||||
}
|
||||
|
||||
void cusb_ep0_out_handler(u8 *buffer, int len) {
|
||||
// This function is trigger when buff_status interrupt is handled
|
||||
// it is called inside cusb_handle_buffer_status
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cusb_start_xfer(void* data, u32 size, EndPointConfiguration *ep){
|
||||
u32 buffer_ctrl = size; // Set data size
|
||||
buffer_ctrl|=ep->next_pid ? BIT_USBCTRL_BUFFER0_PID : 0; // Set DATA0 or DATA1
|
||||
ep->next_pid ^= 1u; // For next transfert
|
||||
|
||||
// Move user data to usb buffer if needed
|
||||
u32 direction=ep->endpoint_descriptor.bEndpointAddress & 0x80;
|
||||
if(direction == USB_DIRECTION_IN){
|
||||
memcpy((void *)ep->buffer0, data, size);
|
||||
buffer_ctrl |= BIT_USBCTRL_BUFFER0_FULL; // Set buffer full for controller
|
||||
// Support for data > 64 bytes (see also cusb_ep0_in_handler())
|
||||
if(size>64){
|
||||
xferremain=size-64;
|
||||
xferptr=((u8*) data)+64;
|
||||
}
|
||||
else {
|
||||
xferremain=0;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup buffer (not available bit yet)
|
||||
*(ep->buffer_control)=buffer_ctrl;
|
||||
|
||||
// Now do available bit (because USB and cores have different clock speed (race condition see p389)
|
||||
asm volatile("nop;nop;nop;"); // ceil(125MHz/48MHz) Should wait 3 cycles see warning p392
|
||||
*(ep->buffer_control)=buffer_ctrl| BIT_USBCTRL_BUFFER0_AVAILABLE; // Apply available bit
|
||||
|
||||
}
|
||||
|
||||
void cusb_eoi(){
|
||||
if(cusb_dc->eoi)
|
||||
cusb_dc->eoi();
|
||||
}
|
||||
|
||||
void cusb_isr_trigger(){
|
||||
REG_WRITE(PPB_NVIC_ISPR, 1u<<5); // Trigger interrupt 5 (USB Controller)
|
||||
}
|
72
src/libs/usb/cusb.h
Normal file
72
src/libs/usb/cusb.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
#include "../types.h"
|
||||
#include "../utils.h"
|
||||
#include "proto.h"
|
||||
|
||||
#define USBCTRL_DPSRAM_SIZE (1024*4) // See p122
|
||||
#define USBCTRL_BUFFER_SIZE 64 // See p385
|
||||
#define USB_ENDPOINT_COUNT 3 // Number of endpoints for the device driver
|
||||
#define USB_INTERFACE_COUNT 2 // Number of interfaces for the device driver
|
||||
#define BCD_USB 0x0110
|
||||
#define USB_BUFFER_OFFSET(ADDR) (ADDR ^ USBCTRL_DPSRAM_BASE) // See here https://github.com/raspberrypi/pico-examples/blob/master/usb/device/dev_lowlevel/dev_lowlevel.c#L141
|
||||
|
||||
typedef struct EndPoint {
|
||||
void *buffer0;
|
||||
void *buffer1;
|
||||
void *rbc; // EP control register
|
||||
volatile u32 *rbc_in; // EP buffer control in register
|
||||
volatile u32 *rbc_out; // EP buffer control out register
|
||||
int next_pid;
|
||||
int is_in;
|
||||
} EndPoint;
|
||||
|
||||
typedef struct EndPointConfiguration{
|
||||
USB_ENDPOINT_DESCRIPTOR endpoint_descriptor;
|
||||
volatile u32* buffer0;
|
||||
volatile u32* buffer1;
|
||||
volatile u32* buffer_control;
|
||||
volatile u32* endpoint_control;
|
||||
u32 next_pid; // Next usb pkt pid (DATA0/DATA1)
|
||||
void (*handler)(u8*,int);
|
||||
} EndPointConfiguration;
|
||||
|
||||
typedef struct FunctionalDescriptors {
|
||||
int size;
|
||||
void* descriptors;
|
||||
} FunctionalDescriptors;
|
||||
|
||||
typedef struct DeviceConfiguration {
|
||||
u8 devaddr; // Current device address
|
||||
u8 setdevaddr; // Set to one when devaddr is available
|
||||
u8 configured; // Set to true when host triggered SET_CONFIGURATION
|
||||
USB_DEVICE_DESCRIPTOR device_descriptor;
|
||||
USB_CONFIGURATION_DESCRIPTOR configuration_descriptor;
|
||||
USB_INTERFACE_DESCRIPTOR interface_descriptors[USB_INTERFACE_COUNT];
|
||||
EndPointConfiguration endpoints[2+USB_ENDPOINT_COUNT]; // Endpoint 0 in and out always required so +2
|
||||
USB_STRING_DESCRIPTOR_ZERO supported_languages;
|
||||
FunctionalDescriptors functional_descriptors;
|
||||
void *full_configuration_descriptor;
|
||||
void (*setup_handler)(UD_SETUP *pkt); // Notify the driver in case of unhandled setup packet
|
||||
void (*setup_ack_handler)(void); // Notify the driver
|
||||
void (*eoi)(void); // Notify the driver for End Of Interrupt
|
||||
char *descriptor_strings[]; // All string like vendor and product id
|
||||
} DeviceConfiguration;
|
||||
|
||||
|
||||
void cusb_init(DeviceConfiguration *dc);
|
||||
void cusb_init_device_configuration();
|
||||
void cusb_ep0_in_handler(u8 *buffer, int len);
|
||||
void cusb_ep0_out_handler(u8 *buffer, int len);
|
||||
void cusb_handle_setup(void);
|
||||
void cusb_handle_bus_reset(void);
|
||||
void cusb_handle_buffer_status(void);
|
||||
int cusb_check_interrupt(int int_bit);
|
||||
void usb_start_xfer(void* data, u32 size, int ep);
|
||||
void cusb_start_xfer(void *data, u32 size, EndPointConfiguration *ep);
|
||||
void cusb_status_xfer(u32 dir);
|
||||
void cusb_eoi(); // Trigger at end of each USB interrupt
|
||||
void cusb_isr_trigger(); // Manually trigger an usb interrupt
|
||||
|
||||
#endif
|
227
src/libs/usb/proto.h
Normal file
227
src/libs/usb/proto.h
Normal file
|
@ -0,0 +1,227 @@
|
|||
#ifndef __PROTO_H__
|
||||
#define __PROTO_H__
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
// ---------- USB Protocol ----------
|
||||
#define USB_DATA typedef struct __attribute__((__packed__))
|
||||
|
||||
// USB token PIDs
|
||||
#define USB_PID_OUT 0b0001
|
||||
#define USB_PID_IN 0b1001
|
||||
#define USB_PID_SOF 0b0101
|
||||
#define USB_PID_SETUP 0b1101
|
||||
|
||||
// USB data PIDs
|
||||
#define USB_PID_DATA0 0b0011
|
||||
#define USB_PID_DATA1 0b1011
|
||||
#define USB_PID_DATA2 0b0111
|
||||
#define USB_PID_MDATA 0b1111
|
||||
|
||||
// Standard Requests Code (bRequest)
|
||||
#define USB_REQUEST_CODE_GET_STATUS 0
|
||||
#define USB_REQUEST_CODE_CLEAR_FEATURE 1
|
||||
#define USB_REQUEST_CODE_SET_FEATURE 3
|
||||
#define USB_REQUEST_CODE_SET_ADDRESS 5
|
||||
#define USB_REQUEST_CODE_GET_DESCRIPTOR 6
|
||||
#define USB_REQUEST_CODE_SET_DESCRIPTOR 7
|
||||
#define USB_REQUEST_CODE_GET_CONFIGURATION 8
|
||||
#define USB_REQUEST_CODE_SET_CONFIGURATION 9
|
||||
#define USB_REQUEST_CODE_GET_INTERFACE 10
|
||||
#define USB_REQUEST_CODE_SET_INTERFACE 11
|
||||
#define USB_REQUEST_CODE_SYNCH_FRAME 12
|
||||
|
||||
// Descriptor Types (wValue)
|
||||
#define USB_DESCRIPTOR_TYPE_DEVICE 1
|
||||
#define USB_DESCRIPTOR_TYPE_CONFIGURATION 2
|
||||
#define USB_DESCRIPTOR_TYPE_STRING 3
|
||||
#define USB_DESCRIPTOR_TYPE_INTERFACE 4
|
||||
#define USB_DESCRIPTOR_TYPE_ENDPOINT 5
|
||||
#define USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 6
|
||||
#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 7
|
||||
#define USB_DESCRIPTOR_TYPE_INTERFACE_POWER 8
|
||||
|
||||
// Feature Selector (wvalue)
|
||||
#define USB_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP 1
|
||||
#define USB_FEATURE_SELECTOR_ENDPOINT_HALT 0
|
||||
#define USB_FEATURE_SELECTOR_TEST_MODE 2
|
||||
|
||||
// Device class code https://developerhelp.microchip.com/xwiki/bin/view/applications/usb/how-it-works/device-classes/
|
||||
#define USB_DEVICE_CLASS_DEVICE 0x00
|
||||
#define USB_DEVICE_CLASS_AUDIO 0x01
|
||||
#define USB_DEVICE_CLASS_CDC 0x02
|
||||
#define USB_DEVICE_CLASS_HID 0x03
|
||||
#define USB_DEVICE_CLASS_PHYSICAL 0x05
|
||||
|
||||
#define USB_TRANSFERT_TYPE_CONTROL 0b00
|
||||
#define USB_TRANSFERT_TYPE_ISOCHRONOUS 0b01
|
||||
#define USB_TRANSFERT_TYPE_BULK 0b10
|
||||
#define USB_TRANSFERT_TYPE_INTERRUPT 0b11
|
||||
|
||||
#define USB_DIRECTION_OUT 0x00
|
||||
#define USB_DIRECTION_IN 0x80
|
||||
|
||||
// Supported languages http://www.baiheee.com/Documents/090518/090518112619/USB_LANGIDs.pdf
|
||||
#define USB_LANG_ENGLISH_US 0x0409
|
||||
#define USB_LANG_ENGLISH_UNITED_KINGDOM 0x0809
|
||||
|
||||
#define B_ENDPOINT_ADDRESS(NUM, DIR) ((NUM)&0xF | (DIR))
|
||||
#define BM_REQUEST_TYPE_DIR_BIT (USB_DIRECTION_IN)
|
||||
|
||||
#define USB_INTERFACE_CLASS_COMMUNICATION 0x02 // Communication interface class
|
||||
#define USB_INTERFACE_CLASS_DATA 0x0a // Data interface class
|
||||
#define USB_INTERFACE_SUBCLASS_ACM 0x02 // Abstract Control Mode
|
||||
#define USB_INTERFACE_COMMUNICATION_PROTOCOL_NOPROTO 0x00 // No protocol
|
||||
|
||||
USB_DATA { // P250
|
||||
u8 bmRequestType;
|
||||
u8 bRequest;
|
||||
u16 wValue;
|
||||
u16 wIndex;
|
||||
u16 wLength;
|
||||
} UD_SETUP;
|
||||
|
||||
// ----- Descriptors -----
|
||||
|
||||
USB_DATA { // P262
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u16 bcdUSB;
|
||||
u8 bDeviceClass;
|
||||
u8 bDeviceSubClass;
|
||||
u8 bDeviceProtocol;
|
||||
u8 bMaxPacketSize0;
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
u16 bcdDevice;
|
||||
u8 iManufacturer;
|
||||
u8 iProduct;
|
||||
u8 iSerialNumber;
|
||||
u8 bNumConfigurations;
|
||||
} USB_DEVICE_DESCRIPTOR;
|
||||
|
||||
|
||||
USB_DATA { // P264 (may not be used in this code)
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u16 bcdUSB;
|
||||
u8 bDeviceClass;
|
||||
u8 bDeviceSubClass;
|
||||
u8 bDeviceProtocol;
|
||||
u8 bMaxPacketSize0;
|
||||
u8 bNumConfigurations;
|
||||
u8 bReserved;
|
||||
} USB_DEVICE_QUALIFIER_DESCRIPTOR;
|
||||
|
||||
USB_DATA { // P265
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u16 wTotalLength;
|
||||
u8 bNumInterfaces;
|
||||
u8 bConfigurationValue;
|
||||
u8 iConfiguration;
|
||||
u8 bmAttributes;
|
||||
u8 bMaxPower;
|
||||
} USB_CONFIGURATION_DESCRIPTOR;
|
||||
|
||||
USB_DATA {
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u16 wTotalLength;
|
||||
u8 bNumInterfaces;
|
||||
u8 bConfigurationValue;
|
||||
u8 iConfiguration;
|
||||
u8 bmAttributes;
|
||||
u8 bMaxPower;
|
||||
} USB_OTHER_SPEED_CONFIGURATION_DESCRIPTOR;
|
||||
|
||||
USB_DATA {
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u8 bInterfaceNumber;
|
||||
u8 bAlternateSetting;
|
||||
u8 bNumEndpoints;
|
||||
u8 bInterfaceClass;
|
||||
u8 bInterfaceSubClass;
|
||||
u8 bInterfaceProtocol;
|
||||
u8 iInterface;
|
||||
} USB_INTERFACE_DESCRIPTOR;
|
||||
|
||||
USB_DATA {
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u8 bEndpointAddress;
|
||||
u8 bmAttributes;
|
||||
u16 wMaxPacketSize;
|
||||
u8 bInterval;
|
||||
} USB_ENDPOINT_DESCRIPTOR;
|
||||
|
||||
USB_DATA {
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
u16 wLANGID0;
|
||||
// Can be more wLANGIDX but stop here!
|
||||
} USB_STRING_DESCRIPTOR_ZERO;
|
||||
|
||||
USB_DATA {
|
||||
u8 bLength;
|
||||
u8 bDescriptorType;
|
||||
// You add your unicode string there
|
||||
} USB_UNICODE_STRING_DESCRIPTOR;
|
||||
|
||||
|
||||
|
||||
|
||||
// ----- CDC Device Class -----
|
||||
// p10 PSTN120.pdf in CDC Specification
|
||||
// p10-.. CDC120-20101103-track.pdf
|
||||
// p10-.. usbcdc11.pdf
|
||||
#define USB_INTERFACE_CLASS_COMMUNICATION 0x02 // Communication interface class
|
||||
#define USB_INTERFACE_CLASS_DATA 0x0a // Data interface class
|
||||
#define USB_INTERFACE_SUBCLASS_ACM 0x02 // Abstract Control Mode
|
||||
#define USB_INTERFACE_COMMUNICATION_PROTOCOL_NOPROTO 0x00 // No protocol
|
||||
|
||||
#define USB_RS232_BMCAPABILITIES 0b10
|
||||
|
||||
#define USB_REQUEST_CODE_SET_LINE_CODING 0x20
|
||||
#define USB_REQUEST_CODE_SET_CONTROL_LINE_STATE 0x22
|
||||
#define USB_REQUEST_CODE_SEND_BREAK 0x23
|
||||
|
||||
// p34
|
||||
USB_DATA {
|
||||
u8 bFunctionLength;
|
||||
u8 bDescriptorType;
|
||||
u8 bDescriptorSubtype;
|
||||
u16 bcdCDC;
|
||||
} USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR;
|
||||
|
||||
// p35
|
||||
USB_DATA {
|
||||
u8 bFunctionLength;
|
||||
u8 bDescriptorType;
|
||||
u8 bDescriptorSubtype;
|
||||
u8 bmCapabilities;
|
||||
} USB_ACM_FUNCTIONAL_DESCRIPTOR;
|
||||
|
||||
// p40
|
||||
USB_DATA {
|
||||
u8 bFunctionLength;
|
||||
u8 bDescriptorType;
|
||||
u8 bDescriptorSubtype;
|
||||
u8 bMasterInterface;
|
||||
u8 bSlaveInterface0;
|
||||
// Can be more! I guess for RS-232 it is enough
|
||||
} USB_UNION_INTERFACE_DESCRIPTOR;
|
||||
|
||||
|
||||
// SEE p49!!!! it is all there it seems
|
||||
// the last descriptor on that page is the "Call management functional
|
||||
// descriptor" (p34). It seems not required according to chatgpt for rs-232
|
||||
USB_DATA {
|
||||
USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR header_descriptor;
|
||||
USB_ACM_FUNCTIONAL_DESCRIPTOR acm_descriptor;
|
||||
USB_UNION_INTERFACE_DESCRIPTOR union_descriptor;
|
||||
} USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR;
|
||||
|
||||
|
||||
#endif
|
53
src/libs/utils.c
Normal file
53
src/libs/utils.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "utils.h"
|
||||
|
||||
void memcpy(u8 *dst, u8 *src, u32 size){
|
||||
for(u32 i=0;i<size;i++){
|
||||
((u8*)(dst))[i]=((u8*)(src))[i];
|
||||
}
|
||||
}
|
||||
|
||||
void memset(u8 *start, u8 value, u32 size){
|
||||
for(u32 i=0;i<size;i++){
|
||||
((u8*)(start))[i]=value;
|
||||
}
|
||||
}
|
||||
|
||||
int modulo(int dividend, int divisor){
|
||||
while((dividend-divisor)>0){dividend-=divisor;}
|
||||
return dividend;
|
||||
}
|
||||
|
||||
int strlen(char * cp)
|
||||
{
|
||||
int len=0;
|
||||
while( cp[len++]) ;
|
||||
return len - 1 ; //because it counted the zero which we don't want.
|
||||
}
|
||||
|
||||
int wordlen(char *s)
|
||||
{
|
||||
int len=0;
|
||||
while( *s!='\n' && *s!='\0' && *s!=' '){ s++; }
|
||||
return len - 1 ; //because it counted the zero which we don't want.
|
||||
}
|
||||
|
||||
u8 strcmp(char *str1, char*str2){
|
||||
while( *str1!='\0' && *str2!='\0'){
|
||||
if(*str1!=*str2)
|
||||
return 1;
|
||||
str1++;
|
||||
str2++;
|
||||
}
|
||||
return *str1 == *str2; // Ensure both final char are \0
|
||||
}
|
||||
|
||||
u8 strncmp(char *str1, char *str2, int n){
|
||||
for(int i=0;i<n;i++){
|
||||
if(str1[i] == '\0' || str2[i] == '\0')
|
||||
break;
|
||||
if(str1[i] != str2[i])
|
||||
return 1;
|
||||
}
|
||||
|
||||
return *str1 != *str2;
|
||||
}
|
30
src/libs/utils.h
Normal file
30
src/libs/utils.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef __UTILS__
|
||||
#define __UTILS__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// General operations
|
||||
#define STR32(ADDR,VALUE) *((volatile unsigned int*) (ADDR))=(VALUE)
|
||||
#define LDR32(ADDR) (*((volatile unsigned int*) (ADDR)))
|
||||
|
||||
// Registers operations
|
||||
#define REG_WRITE(ADDR,VALUE) STR32(ADDR,VALUE)
|
||||
#define REG_WRITE_XOR(ADDR,VALUE) STR32(ADDR+0x1000,VALUE)
|
||||
#define REG_WRITE_BITMAP_SET(ADDR,VALUE) STR32(ADDR+0x2000,VALUE)
|
||||
#define REG_WRITE_BITMAP_CLEAR(ADDR,VALUE) STR32(ADDR+0x3000,VALUE)
|
||||
#define REG_READ(ADDR) LDR32(ADDR)
|
||||
|
||||
// Memory operations
|
||||
void memcpy(u8 *dst, u8 *src, u32 size); // TODO: Improve perf with 32bits memory transactions
|
||||
void memset(u8 *start, u8 value, u32 size); // TODO: Improve perf with 32bits memory transactions
|
||||
|
||||
// Computations
|
||||
int modulo(int dividend, int divisor); // Assumes that both argument are positve (TODO improve this)
|
||||
|
||||
// Strings (not these functions do not follow libc standards and are buggy)
|
||||
int strlen(char * cp);
|
||||
int wordlen(char *s);
|
||||
u8 strcmp(char *str1, char*str2);
|
||||
u8 strncmp(char *str1, char*str2, int n);
|
||||
|
||||
#endif
|
60
src/main.c
Normal file
60
src/main.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "libs/tty.h"
|
||||
#include "libs/utils.h"
|
||||
#include "libs/gpio.h"
|
||||
#include "libs/interrupts.h"
|
||||
#include "libs/clock.h"
|
||||
|
||||
#define MOTD "WELCOME TO RP2040 TTY\n\n\r"
|
||||
#define PROMPT "rp2040> "
|
||||
#define HELP "\tblink\t\tmake led blink for almost 1s\n\r"
|
||||
|
||||
char cmd[64];
|
||||
char *cmdptr=cmd;
|
||||
|
||||
// Execute command from cmd buffer
|
||||
void exec(){
|
||||
if(!strncmp(cmd, "blink", strlen("exit")))
|
||||
gpio_blink_led(1);
|
||||
else if(!strncmp(cmd, "help", strlen("help")))
|
||||
tty_putstr(HELP);
|
||||
else if(cmdptr != cmd)
|
||||
tty_putstr("Unknown command (see help)\n\r");
|
||||
}
|
||||
|
||||
void main(){
|
||||
// Finishing boot
|
||||
interrupts_init();
|
||||
xosc_init();
|
||||
gpio_init();
|
||||
tty_init();
|
||||
|
||||
|
||||
// REPL
|
||||
char c=tty_getchar();
|
||||
tty_putstr(MOTD);
|
||||
tty_putstr(PROMPT);
|
||||
while(1){
|
||||
c=tty_getchar();
|
||||
if(c=='\r'){
|
||||
tty_putstr("\n\r");
|
||||
exec();
|
||||
tty_putstr(PROMPT);
|
||||
cmdptr=cmd;
|
||||
}
|
||||
else if (c ==0x8){
|
||||
if(cmdptr-cmd){
|
||||
tty_putstr("\b \b"); // Erase last character
|
||||
cmdptr--;
|
||||
}
|
||||
}
|
||||
else{
|
||||
*cmdptr=c;
|
||||
cmdptr++;
|
||||
tty_putchar(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue