@@ -16,13 +16,15 @@ LDSCRIPT= sample.ld.gd32vf103
|
||||
### LDSCRIPT= sample.ld.m4
|
||||
### LDSCRIPT= sample.ld
|
||||
### LDSCRIPT= sample.ld.m3
|
||||
CSRC = sample.c
|
||||
CSRC = sample.c usb-vendor-specific.c
|
||||
# CSRC += debug.c
|
||||
|
||||
ARCH=riscv32
|
||||
CHIP=gd32vf103
|
||||
### CHIP=stm32l4
|
||||
### USE_SYS = yes
|
||||
USE_USART = yes
|
||||
USE_USB = yes
|
||||
|
||||
###################################
|
||||
### CROSS = arm-none-eabi-
|
||||
@@ -40,6 +42,7 @@ DEFS = -DFREE_STANDING -DMHZ=96
|
||||
### DEFS = -DFREE_STANDING -DUSE_SYS3 -DBUSY_LOOP -DCHX_FLAGS_MAIN=CHOPSTX_SCHED_RR
|
||||
OPT = -O3 -Os -g
|
||||
LIBS =
|
||||
#LIBS = -lgcc
|
||||
|
||||
CSRC += $(CHOPSTX)/contrib/spi-st.c
|
||||
|
||||
|
||||
34
example-lcd/bouncing_gpg.py
Normal file
34
example-lcd/bouncing_gpg.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from load_image_to_screen import Longan_LCD
|
||||
|
||||
from gnupg_logo_16bit_160x80 import gnupg_logo_16bit_160x80
|
||||
|
||||
image = gnupg_logo_16bit_160x80
|
||||
|
||||
pos = [ 1, 2, 2, 2, 3, 3, 4, 5, 6, 7, 8, 9, 12, 14, 17, 20, 23, 28, 33, 40, 47, 56 ]
|
||||
|
||||
background0 = [ 0x5d, 0xdf ]
|
||||
background1 = [ 0x7e, 0xdf ]
|
||||
|
||||
def fill(i, bg0, bg1):
|
||||
if (i % 2) == 0:
|
||||
return bg0
|
||||
else:
|
||||
return bg1
|
||||
|
||||
def move_right(x, bg0, bg1, img):
|
||||
result = []
|
||||
for i in range(80):
|
||||
for j in range(x):
|
||||
result = result + fill(j, bg0, bg1)
|
||||
result = result + (img[i*160*2:(i+1)*160*2])[0:160*2-x*2]
|
||||
return result
|
||||
|
||||
images = [ bytes(move_right(x, background0, background1, image)) for x in pos ]
|
||||
|
||||
lcd = Longan_LCD()
|
||||
|
||||
for loop in range(10):
|
||||
for i in range(len(pos)):
|
||||
lcd.load_image_to_screen(images[len(pos)-1-i])
|
||||
for i in range(len(pos)):
|
||||
lcd.load_image_to_screen(images[i])
|
||||
26
example-lcd/debug.c
Normal file
26
example-lcd/debug.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <contrib/usart.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern int vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||
|
||||
#define USART_NO 0
|
||||
|
||||
/* Intentionally only adding LF */
|
||||
void
|
||||
debug (const char *fmt, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
size_t len;
|
||||
|
||||
va_start(ap, fmt);
|
||||
len = vsnprintf (buf, sizeof buf - 1, fmt, ap);
|
||||
va_end(ap);
|
||||
if (len >= sizeof buf - 1)
|
||||
len = sizeof buf - 2;
|
||||
buf[len++] = '\n';
|
||||
usart_write (USART_NO, buf, len);
|
||||
}
|
||||
1
example-lcd/debug.h
Normal file
1
example-lcd/debug.h
Normal file
@@ -0,0 +1 @@
|
||||
void debug (const char *fmt, ...);
|
||||
1602
example-lcd/gnupg_logo_16bit_160x80.py
Normal file
1602
example-lcd/gnupg_logo_16bit_160x80.py
Normal file
File diff suppressed because it is too large
Load Diff
96
example-lcd/l.py
Normal file
96
example-lcd/l.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#! /usr/bin/python3
|
||||
|
||||
# pos = [
|
||||
# 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
# 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
|
||||
# 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11,
|
||||
# 12, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 28, 30, 31, 33, 35,
|
||||
# 37, 40, 42, 44, 47, 50, 53, 56, 59, 63, 66, 70, 75, 79, 84, 89, 94,100,105,112,
|
||||
# 118,125,133,141,149,158
|
||||
# ]
|
||||
|
||||
pos = [
|
||||
0, 1, 1, 1,
|
||||
1, 2, 2, 3,
|
||||
4, 6, 8, 11,
|
||||
15, 20, 26, 35,
|
||||
47, 63, 84, 112,
|
||||
149
|
||||
]
|
||||
|
||||
import usb.core
|
||||
import usb.util
|
||||
|
||||
dev = usb.core.find(idVendor=0xffff, idProduct=0x0001)
|
||||
|
||||
if dev is None:
|
||||
raise ValueError('Device not found')
|
||||
|
||||
# dev.set_configuration()
|
||||
|
||||
# get an endpoint instance
|
||||
cfg = dev.get_active_configuration()
|
||||
intf = cfg[(0,0)]
|
||||
|
||||
ep_out = usb.util.find_descriptor(
|
||||
intf,
|
||||
# match the first OUT endpoint
|
||||
custom_match = \
|
||||
lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) == \
|
||||
usb.util.ENDPOINT_OUT)
|
||||
|
||||
ep_in = usb.util.find_descriptor(
|
||||
intf,
|
||||
# match the first IN endpoint
|
||||
custom_match = \
|
||||
lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) == \
|
||||
usb.util.ENDPOINT_IN)
|
||||
|
||||
if ep_out is None:
|
||||
raise ValueError('Endpoint to send data not found')
|
||||
|
||||
if ep_in is None:
|
||||
raise ValueError('Endpoint to receive data not found')
|
||||
|
||||
color_black = [ 0, 0 ]
|
||||
color0 = [ 0xff, 0x03 ]
|
||||
color1 = [ 0xef, 0x7f ]
|
||||
color2 = [ 0x00, 0x78 ]
|
||||
color3 = [ 0xff, 0xff ]
|
||||
|
||||
def gen_image(x):
|
||||
image = []
|
||||
for i in range(80):
|
||||
image = image + (color_black * x) + (color0 * (160-x))
|
||||
return image
|
||||
|
||||
images = [ gen_image(p) for p in pos ]
|
||||
# images = [ gen_image(p) for p in range(160) ]
|
||||
|
||||
import time
|
||||
import sys
|
||||
|
||||
def prepare_send():
|
||||
w=ep_in.read(64)
|
||||
# print(w)
|
||||
|
||||
def finish_send():
|
||||
dev.ctrl_transfer(0x41, 0x00, 0x00, 0x00, "")
|
||||
# print(".", end='', flush=True)
|
||||
|
||||
for i in range(len(images)*8):
|
||||
i0 = i % (len(images)*2)
|
||||
if i0 < len(images):
|
||||
x = (i % len(images))
|
||||
else:
|
||||
x = len(images)- 1 - (i % len(images))
|
||||
# print("%d %d: %d" % (i, x, len(images[x])))
|
||||
if True:
|
||||
prepare_send()
|
||||
ep_out.write(images[x])
|
||||
finish_send()
|
||||
|
||||
prepare_send()
|
||||
dev.ctrl_transfer(0x41, 0x00, 0x01, 0x00, "")
|
||||
51
example-lcd/load_image_to_screen.py
Normal file
51
example-lcd/load_image_to_screen.py
Normal file
@@ -0,0 +1,51 @@
|
||||
#! /usr/bin/python3
|
||||
|
||||
import usb.core
|
||||
import usb.util
|
||||
import time
|
||||
import sys
|
||||
|
||||
class Longan_LCD(object):
|
||||
def __init__(self):
|
||||
self.dev = usb.core.find(idVendor=0xffff, idProduct=0x0001)
|
||||
|
||||
if self.dev is None:
|
||||
raise ValueError('Device not found')
|
||||
|
||||
cfg = self.dev.get_active_configuration()
|
||||
intf = cfg[(0,0)]
|
||||
|
||||
self.ep_out = usb.util.find_descriptor(
|
||||
intf,
|
||||
# match the first OUT endpoint
|
||||
custom_match = \
|
||||
lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) == \
|
||||
usb.util.ENDPOINT_OUT)
|
||||
|
||||
self.ep_in = usb.util.find_descriptor(
|
||||
intf,
|
||||
# match the first IN endpoint
|
||||
custom_match = \
|
||||
lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) == \
|
||||
usb.util.ENDPOINT_IN)
|
||||
|
||||
if self.ep_out is None:
|
||||
raise ValueError('Endpoint to send data not found')
|
||||
|
||||
if self.ep_in is None:
|
||||
raise ValueError('Endpoint to receive data not found')
|
||||
|
||||
def prepare_send(self):
|
||||
w=self.ep_in.read(64)
|
||||
# print(w)
|
||||
|
||||
def finish_send(self):
|
||||
self.dev.ctrl_transfer(0x41, 0x00, 0x00, 0x00, "")
|
||||
# print(".", end='', flush=True)
|
||||
|
||||
def load_image_to_screen(self, image):
|
||||
self.prepare_send()
|
||||
self.ep_out.write(image)
|
||||
self.finish_send()
|
||||
93
example-lcd/longan_usb_load_image.py
Executable file
93
example-lcd/longan_usb_load_image.py
Executable file
@@ -0,0 +1,93 @@
|
||||
#! /usr/bin/python3
|
||||
|
||||
import usb.core
|
||||
import usb.util
|
||||
|
||||
dev = usb.core.find(idVendor=0xffff, idProduct=0x0001)
|
||||
|
||||
if dev is None:
|
||||
raise ValueError('Device not found')
|
||||
|
||||
# dev.set_configuration()
|
||||
|
||||
# get an endpoint instance
|
||||
cfg = dev.get_active_configuration()
|
||||
intf = cfg[(0,0)]
|
||||
|
||||
ep_out = usb.util.find_descriptor(
|
||||
intf,
|
||||
# match the first OUT endpoint
|
||||
custom_match = \
|
||||
lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) == \
|
||||
usb.util.ENDPOINT_OUT)
|
||||
|
||||
ep_in = usb.util.find_descriptor(
|
||||
intf,
|
||||
# match the first IN endpoint
|
||||
custom_match = \
|
||||
lambda e: \
|
||||
usb.util.endpoint_direction(e.bEndpointAddress) == \
|
||||
usb.util.ENDPOINT_IN)
|
||||
|
||||
if ep_out is None:
|
||||
raise ValueError('Endpoint to send data not found')
|
||||
|
||||
if ep_in is None:
|
||||
raise ValueError('Endpoint to receive data not found')
|
||||
|
||||
def prepare_send():
|
||||
w=ep_in.read(64)
|
||||
# print(w)
|
||||
|
||||
def finish_send():
|
||||
dev.ctrl_transfer(0x41, 0x00, 0x00, 0x00, "")
|
||||
# print(".", end='', flush=True)
|
||||
|
||||
|
||||
color0 = [ 0xff, 0x03 ]
|
||||
color1 = [ 0xef, 0x7f ]
|
||||
color2 = [ 0x00, 0x78 ]
|
||||
color3 = [ 0xff, 0xff ]
|
||||
|
||||
image = color0*160*80
|
||||
# + color1*160*40
|
||||
image64 = color0*32
|
||||
image = color1*160*80
|
||||
point1600a=(color0*40+color1*40)*20
|
||||
point1600b=(color1*40+color0*40)*20
|
||||
|
||||
point1600c=(color2*20+color3*20)*40
|
||||
point1600d=(color3*20+color2*20)*40
|
||||
|
||||
import time
|
||||
import sys
|
||||
|
||||
for i in range(10):
|
||||
prepare_send()
|
||||
|
||||
ep_out.write(point1600a)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600b)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600a)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600b)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600a)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600b)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600a)
|
||||
print(".", end='', flush=True)
|
||||
ep_out.write(point1600b)
|
||||
print(".")
|
||||
finish_send()
|
||||
|
||||
prepare_send()
|
||||
ep_out.write(point1600c*2+point1600d*2+point1600c*2+point1600d*2)
|
||||
print(".")
|
||||
finish_send()
|
||||
|
||||
prepare_send()
|
||||
dev.ctrl_transfer(0x41, 0x00, 0x01, 0x00, "")
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
#include <mcu/gd32vf103.h>
|
||||
|
||||
#include "vrsp.h"
|
||||
|
||||
void
|
||||
set_led_b (void)
|
||||
{
|
||||
@@ -33,91 +35,13 @@ set_led (int on)
|
||||
GPIOC->ODR |= (1 << 13);
|
||||
}
|
||||
|
||||
static chopstx_mutex_t mtx;
|
||||
static chopstx_cond_t cnd0;
|
||||
static chopstx_cond_t cnd1;
|
||||
|
||||
static uint8_t u, v;
|
||||
static uint8_t m; /* 0..100 */
|
||||
|
||||
static void
|
||||
wait_for (uint32_t usec)
|
||||
{
|
||||
#if defined(BUSY_LOOP)
|
||||
uint32_t count = usec * 6;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
asm volatile ("" : : "r" (i) : "memory");
|
||||
#else
|
||||
chopstx_usec_wait (usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *
|
||||
pwm (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd0, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
set_led (u&v);
|
||||
wait_for (m);
|
||||
set_led (0);
|
||||
wait_for (100-m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
blk (void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_wait (&cnd1, &mtx);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
while (1)
|
||||
{
|
||||
v = 0;
|
||||
wait_for (200*1000);
|
||||
v = 1;
|
||||
wait_for (200*1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(BUSY_LOOP)
|
||||
#define PRIO_PWM (CHOPSTX_SCHED_RR|1)
|
||||
#define PRIO_BLK (CHOPSTX_SCHED_RR|1)
|
||||
#else
|
||||
#define PRIO_PWM 3
|
||||
#define PRIO_BLK 2
|
||||
#endif
|
||||
|
||||
#define STACK_MAIN
|
||||
#define STACK_PROCESS_1
|
||||
#define STACK_PROCESS_2
|
||||
#define STACK_PROCESS_3
|
||||
#include "stack-def.h"
|
||||
|
||||
|
||||
#define STACK_ADDR_PWM ((uint32_t)process1_base)
|
||||
#define STACK_SIZE_PWM (sizeof process1_base)
|
||||
|
||||
#define STACK_ADDR_BLK ((uint32_t)process2_base)
|
||||
#define STACK_SIZE_BLK (sizeof process2_base)
|
||||
|
||||
#define PRIO_USART 4
|
||||
#define STACK_ADDR_USART ((uint32_t)process3_base)
|
||||
#define STACK_SIZE_USART (sizeof process3_base)
|
||||
#define PRIO_USART 3
|
||||
#define STACK_ADDR_USART ((uint32_t)process1_base)
|
||||
#define STACK_SIZE_USART (sizeof process1_base)
|
||||
|
||||
#define LCD_WIDTH 160
|
||||
#define LCD_HEIGHT 80
|
||||
@@ -168,10 +92,8 @@ lcd_control (int control)
|
||||
static void
|
||||
lcd_send (uint8_t data)
|
||||
{
|
||||
lcd_chip_select (1);
|
||||
spi_send (data);
|
||||
spi_recv ();
|
||||
lcd_chip_select (0);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -206,13 +128,14 @@ lcd_init (void)
|
||||
lcd_reset (1);
|
||||
chopstx_usec_wait (500*1000);
|
||||
lcd_reset (0);
|
||||
chopstx_usec_wait (50*1000);
|
||||
lcd_chip_select (1);
|
||||
chopstx_usec_wait (100*1000);
|
||||
|
||||
lcd_command (0x11); /* SLPOUT: Sleep out */
|
||||
chopstx_usec_wait (100*1000);
|
||||
|
||||
lcd_command (0x21); /* INVON: display inversion on */
|
||||
/* INVOFF: display inversion off: 0x20 */
|
||||
/* INVOFF: display inversion off: 0x20 */
|
||||
|
||||
lcd_command (0x3a); /* COLMOD: Pixel data format */
|
||||
lcd_data8 (0x05); /* 16-bit/pixel */
|
||||
@@ -356,72 +279,93 @@ ss_notify (uint8_t dev_no, uint16_t state_bits)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "fsij-logo.c"
|
||||
uint16_t screen_image[12800];
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
chopstx_poll_cond_t poll_desc;
|
||||
struct chx_poll_head *ph[1];
|
||||
chopstx_poll_cond_t usart_poll_desc;
|
||||
chopstx_poll_cond_t usb_poll_desc;
|
||||
struct chx_poll_head *ph[2];
|
||||
uint32_t timeout;
|
||||
int cl = 0;
|
||||
int play_mode = 0;
|
||||
struct vrsp *v;
|
||||
uint32_t u = 0;
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
set_led (1);
|
||||
|
||||
chopstx_mutex_init (&mtx);
|
||||
chopstx_cond_init (&cnd0);
|
||||
chopstx_cond_init (&cnd1);
|
||||
|
||||
m = 10;
|
||||
|
||||
chopstx_create (PRIO_PWM, STACK_ADDR_PWM, STACK_SIZE_PWM, pwm, NULL);
|
||||
chopstx_create (PRIO_BLK, STACK_ADDR_BLK, STACK_SIZE_BLK, blk, NULL);
|
||||
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_signal (&cnd0);
|
||||
chopstx_cond_signal (&cnd1);
|
||||
chopstx_mutex_unlock (&mtx);
|
||||
|
||||
lcd_init ();
|
||||
|
||||
usart_init (PRIO_USART, STACK_ADDR_USART, STACK_SIZE_USART, ss_notify);
|
||||
usart_config (0, B115200 | CS8 | STOP1B);
|
||||
|
||||
usart_read_prepare_poll (0, &poll_desc);
|
||||
ph[0] = (struct chx_poll_head *)&poll_desc;
|
||||
v = vrsp_open ();
|
||||
|
||||
chopstx_usec_wait (500*1000);
|
||||
set_led (1);
|
||||
|
||||
lcd_init ();
|
||||
lcd_clear (colors[26]);
|
||||
|
||||
chopstx_usec_wait (500*1000);
|
||||
|
||||
vrsp_prepare_poll (v, &usb_poll_desc);
|
||||
ph[0] = (struct chx_poll_head *)&usb_poll_desc;
|
||||
|
||||
usart_read_prepare_poll (0, &usart_poll_desc);
|
||||
ph[1] = (struct chx_poll_head *)&usart_poll_desc;
|
||||
|
||||
timeout = 200*1000*6;
|
||||
while (1)
|
||||
{
|
||||
chopstx_poll (&timeout, 1, ph);
|
||||
chopstx_poll (&timeout, 2, ph);
|
||||
|
||||
if (usart_poll_desc.ready)
|
||||
{
|
||||
char buf[16];
|
||||
int r;
|
||||
r = usart_read (0, buf, 16);
|
||||
if (r)
|
||||
usart_write (0, buf, r);
|
||||
}
|
||||
|
||||
if (usb_poll_desc.ready)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = vrsp_screen_acquire (v);
|
||||
if (r < 0)
|
||||
/* It's busy. */
|
||||
;
|
||||
else if (r == 0)
|
||||
{
|
||||
play_mode = 1;
|
||||
lcd_load_image (screen_image);
|
||||
vrsp_screen_release (v);
|
||||
}
|
||||
else
|
||||
{
|
||||
play_mode = 0;
|
||||
vrsp_screen_release (v);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
usart_write (0, "Hello\r\n", 7);
|
||||
u ^= 1;
|
||||
timeout = 200*1000*6;
|
||||
|
||||
lcd_clear (colors[cl]);
|
||||
u ^= 1;
|
||||
set_led (u);
|
||||
|
||||
chopstx_usec_wait (1000*1000);
|
||||
lcd_load_image (fsij_logo);
|
||||
chopstx_usec_wait (1000*1000);
|
||||
if (play_mode == 0)
|
||||
{
|
||||
lcd_clear (colors[cl]);
|
||||
|
||||
cl++;
|
||||
if (cl >= 27)
|
||||
cl = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[256];
|
||||
int r;
|
||||
r = usart_read (0, buf, 256);
|
||||
if (r)
|
||||
usart_write (0, buf, r);
|
||||
cl++;
|
||||
if (cl >= 27)
|
||||
cl = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ SECTIONS
|
||||
*(.process_stack.1)
|
||||
*(.process_stack.2)
|
||||
*(.process_stack.3)
|
||||
*(.process_stack.4)
|
||||
. = ALIGN(8);
|
||||
} > ram
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#define MAIN_SIZE 0x0100 /* Idle+Exception handlers */
|
||||
#define SIZE_0 0x0400 /* Main program */
|
||||
#define SIZE_1 0x0200 /* first thread program */
|
||||
#define SIZE_2 0x0200 /* second thread program */
|
||||
#define SIZE_3 0x0600 /* second thread program */
|
||||
#define SIZE_0 0x0600 /* Main program */
|
||||
#define SIZE_1 0x0c00 /* first thread program */
|
||||
#define SIZE_2 0x0600 /* second thread program */
|
||||
#define SIZE_3 0x0000 /* third thread program */
|
||||
#define SIZE_4 0x0000 /* fourth thread program */
|
||||
|
||||
#if defined(STACK_MAIN)
|
||||
/*
|
||||
|
||||
585
example-lcd/usb-vendor-specific.c
Normal file
585
example-lcd/usb-vendor-specific.c
Normal file
@@ -0,0 +1,585 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <chopstx.h>
|
||||
#include <string.h>
|
||||
#include "board.h"
|
||||
#include "usb_lld.h"
|
||||
#include "vrsp.h"
|
||||
|
||||
extern uint16_t screen_image[12800];
|
||||
|
||||
static chopstx_intr_t usb_intr;
|
||||
|
||||
struct vrsp {
|
||||
struct usb_dev dev;
|
||||
chopstx_mutex_t mtx;
|
||||
chopstx_cond_t cnd;
|
||||
uint32_t device_state : 3; /* USB device status */
|
||||
uint32_t screen_mem_owner : 1; /* 0: driver, 1: app */
|
||||
uint32_t mode : 8;
|
||||
uint16_t *screen_ptr;
|
||||
};
|
||||
|
||||
static struct vrsp vrsp0;
|
||||
|
||||
/*
|
||||
* Locate VRSP structure from interface number or endpoint number.
|
||||
* Currently, it always returns vrsp0, because we only have the one.
|
||||
*/
|
||||
static struct vrsp *
|
||||
vrsp_get (int interface, uint8_t ep_num)
|
||||
{
|
||||
struct vrsp *v = &vrsp0;
|
||||
|
||||
(void)interface;
|
||||
(void)ep_num;
|
||||
return v;
|
||||
}
|
||||
|
||||
static void vrsp_update_finish (struct vrsp *v, int value);
|
||||
|
||||
/* USB Device Descriptor */
|
||||
static const uint8_t vrsp_device_desc[18] = {
|
||||
18, /* bLength */
|
||||
DEVICE_DESCRIPTOR, /* bDescriptorType */
|
||||
0x10, 0x01, /* bcdUSB = 1.1 */
|
||||
0x00, /* bDeviceClass. */
|
||||
0x00, /* bDeviceSubClass. */
|
||||
0x00, /* bDeviceProtocol. */
|
||||
0x40, /* bMaxPacketSize. */
|
||||
0xFF, 0xFF, /* idVendor */
|
||||
0x01, 0x00, /* idProduct */
|
||||
0x00, 0x01, /* bcdDevice */
|
||||
1, /* iManufacturer. */
|
||||
2, /* iProduct. */
|
||||
3, /* iSerialNumber. */
|
||||
1 /* bNumConfigurations. */
|
||||
};
|
||||
|
||||
#define FEATURE_BUS_POWERED 0x80
|
||||
|
||||
/* Configuration Descriptor */
|
||||
static const uint8_t vrsp_config_desc[32] = {
|
||||
9,
|
||||
CONFIG_DESCRIPTOR, /* bDescriptorType: Configuration */
|
||||
/* Configuration Descriptor.*/
|
||||
32, 0x00, /* wTotalLength. */
|
||||
0x01, /* bNumInterfaces. */
|
||||
0x01, /* bConfigurationValue. */
|
||||
0, /* iConfiguration. */
|
||||
FEATURE_BUS_POWERED, /* bmAttributes. */
|
||||
50, /* bMaxPower (100mA). */
|
||||
/* Interface Descriptor.*/
|
||||
9,
|
||||
INTERFACE_DESCRIPTOR,
|
||||
0x00, /* bInterfaceNumber. */
|
||||
0x00, /* bAlternateSetting. */
|
||||
0x02, /* bNumEndpoints. */
|
||||
0xFF, /* bInterfaceClass (Vendor specific). */
|
||||
0x00, /* bInterfaceSubClass. */
|
||||
0x00, /* bInterfaceProtocol. */
|
||||
0, /* iInterface. */
|
||||
/* Endpoint 1-OUT Descriptor.*/
|
||||
7,
|
||||
ENDPOINT_DESCRIPTOR,
|
||||
ENDP1, /* bEndpointAddress. */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval. */
|
||||
/* Endpoint 1-IN Descriptor.*/
|
||||
7,
|
||||
ENDPOINT_DESCRIPTOR,
|
||||
ENDP1|0x80, /* bEndpointAddress. */
|
||||
0x02, /* bmAttributes (Bulk). */
|
||||
0x40, 0x00, /* wMaxPacketSize. */
|
||||
0x00, /* bInterval. */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* U.S. English language identifier.
|
||||
*/
|
||||
static const uint8_t vrsp_string0[4] = {
|
||||
4, /* bLength */
|
||||
STRING_DESCRIPTOR,
|
||||
0x09, 0x04 /* LangID = 0x0409: US-English */
|
||||
};
|
||||
|
||||
static const uint8_t vrsp_string1[] = {
|
||||
23*2+2, /* bLength */
|
||||
STRING_DESCRIPTOR, /* bDescriptorType */
|
||||
/* Manufacturer: "Flying Stone Technology" */
|
||||
'F', 0, 'l', 0, 'y', 0, 'i', 0, 'n', 0, 'g', 0, ' ', 0, 'S', 0,
|
||||
't', 0, 'o', 0, 'n', 0, 'e', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0,
|
||||
'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'y', 0,
|
||||
};
|
||||
|
||||
static const uint8_t vrsp_string2[] = {
|
||||
14*2+2, /* bLength */
|
||||
STRING_DESCRIPTOR, /* bDescriptorType */
|
||||
/* Product name: "Chopstx Sample" */
|
||||
'C', 0, 'h', 0, 'o', 0, 'p', 0, 's', 0, 't', 0, 'x', 0, ' ', 0,
|
||||
'S', 0, 'a', 0, 'm', 0, 'p', 0, 'l', 0, 'e', 0,
|
||||
};
|
||||
|
||||
/*
|
||||
* Serial Number string.
|
||||
*/
|
||||
static const uint8_t vrsp_string3[10] = {
|
||||
10, /* bLength */
|
||||
STRING_DESCRIPTOR, /* bDescriptorType */
|
||||
'0', 0, '.', 0, '0', 0, '0', 0, /* Version number */
|
||||
};
|
||||
|
||||
#define NUM_INTERFACES 1
|
||||
|
||||
static void
|
||||
usb_device_reset (struct usb_dev *dev)
|
||||
{
|
||||
usb_lld_reset (dev, FEATURE_BUS_POWERED);
|
||||
|
||||
chopstx_mutex_lock (&vrsp0.mtx);
|
||||
vrsp0.device_state = USB_DEVICE_STATE_ATTACHED;
|
||||
vrsp0.screen_mem_owner = 0;
|
||||
vrsp0.screen_ptr = screen_image;
|
||||
vrsp0.mode = 2;
|
||||
chopstx_cond_signal (&vrsp0.cnd);
|
||||
chopstx_mutex_unlock (&vrsp0.mtx);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_ctrl_write_finish (struct usb_dev *dev)
|
||||
{
|
||||
(void)dev;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_setup (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t type_rcp = arg->type & (REQUEST_TYPE|RECIPIENT);
|
||||
|
||||
if (USB_SETUP_SET (arg->type))
|
||||
{
|
||||
if (type_rcp == (VENDOR_REQUEST | INTERFACE_RECIPIENT)
|
||||
&& arg->request == 0x00
|
||||
&& arg->index == 0 /* interface 0 */)
|
||||
{
|
||||
struct vrsp *v = vrsp_get (arg->index, 0);
|
||||
|
||||
/* Finish the screen update. */
|
||||
vrsp_update_finish (v, arg->value);
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_descriptor (struct usb_dev *dev)
|
||||
{
|
||||
struct device_req *arg = &dev->dev_req;
|
||||
uint8_t rcp = arg->type & RECIPIENT;
|
||||
uint8_t desc_type = (arg->value >> 8);
|
||||
uint8_t desc_index = (arg->value & 0xff);
|
||||
|
||||
if (rcp != DEVICE_RECIPIENT)
|
||||
return -1;
|
||||
|
||||
if (desc_type == DEVICE_DESCRIPTOR)
|
||||
return usb_lld_ctrl_send (dev,
|
||||
vrsp_device_desc, sizeof (vrsp_device_desc));
|
||||
else if (desc_type == CONFIG_DESCRIPTOR)
|
||||
return usb_lld_ctrl_send (dev,
|
||||
vrsp_config_desc, sizeof (vrsp_config_desc));
|
||||
else if (desc_type == STRING_DESCRIPTOR)
|
||||
{
|
||||
const uint8_t *str;
|
||||
int size;
|
||||
|
||||
switch (desc_index)
|
||||
{
|
||||
case 0:
|
||||
str = vrsp_string0;
|
||||
size = sizeof (vrsp_string0);
|
||||
break;
|
||||
case 1:
|
||||
str = vrsp_string1;
|
||||
size = sizeof (vrsp_string1);
|
||||
break;
|
||||
case 2:
|
||||
str = vrsp_string2;
|
||||
size = sizeof (vrsp_string2);
|
||||
break;
|
||||
case 3:
|
||||
str = vrsp_string3;
|
||||
size = sizeof (vrsp_string3);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return usb_lld_ctrl_send (dev, str, size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const uint8_t status_zero;
|
||||
|
||||
static void
|
||||
vrsp_setup_endpoints_for_interface (struct usb_dev *dev,
|
||||
uint16_t interface, int stop)
|
||||
{
|
||||
if (interface == 0)
|
||||
{
|
||||
if (!stop)
|
||||
{
|
||||
struct vrsp *v = vrsp_get (interface, 0);
|
||||
|
||||
usb_lld_setup_endp (dev, ENDP1, EP_BULK, 1, 1);
|
||||
|
||||
if (v->screen_mem_owner == 0)
|
||||
usb_lld_tx_enable_buf (&v->dev, ENDP1, &status_zero, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_lld_stall_rx (dev, ENDP1);
|
||||
usb_lld_stall_tx (dev, ENDP1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
usb_set_configuration (struct usb_dev *dev)
|
||||
{
|
||||
uint8_t current_conf;
|
||||
|
||||
current_conf = usb_lld_current_configuration (dev);
|
||||
if (current_conf == 0)
|
||||
{
|
||||
if (dev->dev_req.value != 1)
|
||||
return -1;
|
||||
|
||||
usb_lld_set_configuration (dev, 1);
|
||||
vrsp_setup_endpoints_for_interface (dev, 0, 0);
|
||||
}
|
||||
else if (current_conf != dev->dev_req.value)
|
||||
{
|
||||
if (dev->dev_req.value != 0)
|
||||
return -1;
|
||||
|
||||
usb_lld_set_configuration (dev, 0);
|
||||
vrsp_setup_endpoints_for_interface (dev, 0, 1);
|
||||
}
|
||||
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
usb_set_interface (struct usb_dev *dev)
|
||||
{
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
uint16_t alt = dev->dev_req.value;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
if (alt != 0)
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
vrsp_setup_endpoints_for_interface (dev, interface, 0);
|
||||
return usb_lld_ctrl_ack (dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint8_t zero = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
/* We don't have alternate interface, so, always return 0. */
|
||||
return usb_lld_ctrl_send (dev, &zero, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
usb_get_status_interface (struct usb_dev *dev)
|
||||
{
|
||||
const uint16_t status_info = 0;
|
||||
uint16_t interface = dev->dev_req.index;
|
||||
|
||||
if (interface >= NUM_INTERFACES)
|
||||
return -1;
|
||||
|
||||
return usb_lld_ctrl_send (dev, &status_info, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
vrsp_update_receive (struct vrsp *v, int len)
|
||||
{
|
||||
chopstx_mutex_lock (&v->mtx);
|
||||
if (v->screen_mem_owner == 0 && v->screen_ptr)
|
||||
{
|
||||
v->screen_ptr += len / 2;
|
||||
if (v->screen_ptr < screen_image + 12800)
|
||||
usb_lld_rx_enable_buf (&v->dev, ENDP1, v->screen_ptr, 64);
|
||||
}
|
||||
chopstx_mutex_unlock (&v->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
vrsp_update_finish (struct vrsp *v, int value)
|
||||
{
|
||||
chopstx_mutex_lock (&v->mtx);
|
||||
if (v->screen_mem_owner == 0 && v->screen_ptr)
|
||||
{
|
||||
v->screen_ptr = NULL;
|
||||
v->mode = value;
|
||||
chopstx_cond_signal (&v->cnd);
|
||||
}
|
||||
chopstx_mutex_unlock (&v->mtx);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_tx_done (uint8_t ep_num, uint16_t len)
|
||||
{
|
||||
struct vrsp *v = vrsp_get (-1, ep_num);
|
||||
|
||||
(void)len;
|
||||
|
||||
/*
|
||||
* Coming here means that notification ("it's ready to accept screen
|
||||
* data") is retrieved by host. Enable the receive endpoint to
|
||||
* accept data.
|
||||
*/
|
||||
|
||||
/* EP_NUM should be ENDP1 in this implementation. */
|
||||
usb_lld_rx_enable_buf (&v->dev, ENDP1, v->screen_ptr, 64);
|
||||
}
|
||||
|
||||
static void
|
||||
usb_rx_ready (uint8_t ep_num, uint16_t len)
|
||||
{
|
||||
struct vrsp *v = vrsp_get (-1, ep_num);
|
||||
|
||||
if (ep_num == ENDP1)
|
||||
vrsp_update_receive (v, len);
|
||||
}
|
||||
|
||||
#define PRIO_VRSP 4
|
||||
|
||||
#define STACK_PROCESS_2
|
||||
#include "stack-def.h"
|
||||
#define STACK_ADDR_VRSP ((uint32_t)process2_base)
|
||||
#define STACK_SIZE_VRSP (sizeof process2_base)
|
||||
|
||||
static void *
|
||||
vrsp_main (void *arg)
|
||||
{
|
||||
struct vrsp *v = arg;
|
||||
struct usb_dev *dev = &v->dev;
|
||||
int e;
|
||||
|
||||
chopstx_claim_irq (&usb_intr, INTR_REQ_USB);
|
||||
usb_lld_init (dev, FEATURE_BUS_POWERED);
|
||||
|
||||
while (1)
|
||||
{
|
||||
chopstx_intr_wait (&usb_intr);
|
||||
if (usb_intr.ready)
|
||||
{
|
||||
uint8_t ep_num;
|
||||
|
||||
/*
|
||||
* When interrupt is detected, call usb_lld_event_handler.
|
||||
* The event may be one of following:
|
||||
* (1) Transfer to endpoint (bulk or interrupt)
|
||||
* In this case EP_NUM is encoded in the variable E.
|
||||
* (2) "NONE" event: some trasfer was done, but all was
|
||||
* done by lower layer, no other work is needed in
|
||||
* upper layer.
|
||||
* (3) Device events: Reset or Suspend
|
||||
* (4) Device requests to the endpoint zero.
|
||||
*
|
||||
*/
|
||||
e = usb_lld_event_handler (dev);
|
||||
chopstx_intr_done (&usb_intr);
|
||||
ep_num = USB_EVENT_ENDP (e);
|
||||
|
||||
if (ep_num != 0)
|
||||
{
|
||||
if (USB_EVENT_TXRX (e))
|
||||
usb_tx_done (ep_num, USB_EVENT_LEN (e));
|
||||
else
|
||||
usb_rx_ready (ep_num, USB_EVENT_LEN (e));
|
||||
}
|
||||
else
|
||||
switch (USB_EVENT_ID (e))
|
||||
{
|
||||
case USB_EVENT_DEVICE_RESET:
|
||||
usb_device_reset (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_DEVICE_ADDRESSED:
|
||||
/* The addres is assigned to the device. We don't
|
||||
* need to do anything for this actually, but in this
|
||||
* application, we maintain the USB status of the
|
||||
* device. Usually, just "continue" as EVENT_OK is
|
||||
* OK.
|
||||
*/
|
||||
chopstx_mutex_lock (&v->mtx);
|
||||
v->device_state = USB_DEVICE_STATE_ADDRESSED;
|
||||
chopstx_cond_signal (&v->cnd);
|
||||
chopstx_mutex_unlock (&v->mtx);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_DESCRIPTOR:
|
||||
if (usb_get_descriptor (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_CONFIGURATION:
|
||||
if (usb_set_configuration (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_INTERFACE:
|
||||
if (usb_set_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_CTRL_REQUEST:
|
||||
/* Device specific device request. */
|
||||
if (usb_setup (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_STATUS_INTERFACE:
|
||||
if (usb_get_status_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_GET_INTERFACE:
|
||||
if (usb_get_interface (dev) < 0)
|
||||
usb_lld_ctrl_error (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_SET_FEATURE_DEVICE:
|
||||
case USB_EVENT_SET_FEATURE_ENDPOINT:
|
||||
case USB_EVENT_CLEAR_FEATURE_DEVICE:
|
||||
case USB_EVENT_CLEAR_FEATURE_ENDPOINT:
|
||||
usb_lld_ctrl_ack (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_CTRL_WRITE_FINISH:
|
||||
/* Control WRITE transfer finished. */
|
||||
usb_ctrl_write_finish (dev);
|
||||
continue;
|
||||
|
||||
case USB_EVENT_OK:
|
||||
case USB_EVENT_DEVICE_SUSPEND:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
vrsp_ready_check (void *arg)
|
||||
{
|
||||
struct vrsp *v = arg;
|
||||
return v->screen_mem_owner == 0 && v->screen_ptr == NULL;
|
||||
}
|
||||
|
||||
|
||||
/* API exposed to application. */
|
||||
|
||||
struct vrsp *
|
||||
vrsp_open (void)
|
||||
{
|
||||
struct vrsp *v = &vrsp0; /* Now, we only have a single VRSP. */
|
||||
|
||||
chopstx_mutex_init (&v->mtx);
|
||||
chopstx_cond_init (&v->cnd);
|
||||
v->device_state = USB_DEVICE_STATE_UNCONNECTED;
|
||||
v->screen_mem_owner = 0;
|
||||
v->screen_ptr = screen_image;
|
||||
v->mode = 1;
|
||||
|
||||
chopstx_create (PRIO_VRSP, STACK_ADDR_VRSP, STACK_SIZE_VRSP, vrsp_main, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vrsp_prepare_poll (struct vrsp *v, chopstx_poll_cond_t *poll_desc)
|
||||
{
|
||||
poll_desc->type = CHOPSTX_POLL_COND;
|
||||
poll_desc->ready = 0;
|
||||
poll_desc->cond = &v->cnd;
|
||||
poll_desc->mutex = &v->mtx;
|
||||
poll_desc->check = vrsp_ready_check;
|
||||
poll_desc->arg = v;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vrsp_screen_acquire: Acquire the screen memory by the application to
|
||||
* update the LCD.
|
||||
*
|
||||
* Returns < 0 on error
|
||||
* >= 0 on success
|
||||
*/
|
||||
int
|
||||
vrsp_screen_acquire (struct vrsp *v)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
chopstx_mutex_lock (&v->mtx);
|
||||
while (1)
|
||||
if (v->screen_mem_owner != 0)
|
||||
{
|
||||
/* something goes wrong, it's your turn already. */
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
else if (v->screen_ptr)
|
||||
/* The use of screen has not been finished yet. */
|
||||
chopstx_cond_wait (&v->cnd, &v->mtx);
|
||||
else
|
||||
{
|
||||
v->screen_mem_owner = 1;
|
||||
r = v->mode;
|
||||
break;
|
||||
}
|
||||
chopstx_mutex_unlock (&v->mtx);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vrsp_screen_release: release the screen memory by the application
|
||||
*/
|
||||
void
|
||||
vrsp_screen_release (struct vrsp *v)
|
||||
{
|
||||
chopstx_mutex_lock (&v->mtx);
|
||||
v->screen_mem_owner = 0;
|
||||
v->screen_ptr = screen_image;
|
||||
chopstx_mutex_unlock (&v->mtx);
|
||||
|
||||
/* Put the notification to host. */
|
||||
usb_lld_tx_enable_buf (&v->dev, ENDP1, &status_zero, 1);
|
||||
}
|
||||
7
example-lcd/vrsp.h
Normal file
7
example-lcd/vrsp.h
Normal file
@@ -0,0 +1,7 @@
|
||||
struct vrsp;
|
||||
|
||||
struct vrsp *vrsp_open (void);
|
||||
|
||||
void vrsp_prepare_poll (struct vrsp *v, chopstx_poll_cond_t *poll_desc);
|
||||
int vrsp_screen_acquire (struct vrsp *v);
|
||||
void vrsp_screen_release (struct vrsp *v);
|
||||
Reference in New Issue
Block a user