diff --git a/F3:F303/PL2303/Makefile b/F3:F303/PL2303/Makefile index 3bd1054..a6e9467 100644 --- a/F3:F303/PL2303/Makefile +++ b/F3:F303/PL2303/Makefile @@ -3,6 +3,7 @@ BINARY := pl2303 MCU := F303xb # change this linking script depending on particular MCU model, LDSCRIPT := stm32f303xB.ld +DEFINES := -DUSB1_16 include ../makefile.f3 include ../../makefile.stm32 diff --git a/F3:F303/PL2303/hardware.c b/F3:F303/PL2303/hardware.c index c6a169a..4865cc7 100644 --- a/F3:F303/PL2303/hardware.c +++ b/F3:F303/PL2303/hardware.c @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -20,10 +20,15 @@ #include "usart.h" static inline void gpio_setup(){ - RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs - for(int i = 0; i < 10000; ++i) nop(); + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; + // LEDs on PB0 and PB1 GPIOB->MODER = GPIO_MODER_MODER0_O | GPIO_MODER_MODER1_O; GPIOB->ODR = 1; + // USB - alternate function 14 @ pins PA11/PA12; USART1 = AF7 @PA9/10; SWD - AF0 @PA13/14 + GPIOA->AFR[1] = AFRf(7, 9) | AFRf(7, 10) | AFRf(14, 11) | AFRf(14, 12); + // USART1: PA10(Rx), PA9(Tx); USB - PA11, PA12; SWDIO - PA13, PA14; Pullup - PA15 + GPIOA->MODER = MODER_AF(9) | MODER_AF(10) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15); + GPIOA->OSPEEDR = OSPEED_HI(11) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14); } void hw_setup(){ diff --git a/F3:F303/PL2303/hardware.h b/F3:F303/PL2303/hardware.h index 91dfdc5..e90238f 100644 --- a/F3:F303/PL2303/hardware.h +++ b/F3:F303/PL2303/hardware.h @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -22,6 +22,11 @@ #include +#define USBPU_port GPIOA +#define USBPU_pin (1<<15) +#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) +#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) + extern volatile uint32_t Tms; void hw_setup(); diff --git a/F3:F303/PL2303/main.c b/F3:F303/PL2303/main.c index 6f9c39b..f47513b 100644 --- a/F3:F303/PL2303/main.c +++ b/F3:F303/PL2303/main.c @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -35,6 +35,7 @@ void sys_tick_handler(void){ int main(void){ char inbuff[MAXSTRLEN+1]; int hse = 0; + USBPU_OFF(); if(StartHSE()){ hse = 1; SysTick_Config((uint32_t)72000); // 1ms @@ -45,6 +46,7 @@ int main(void){ hw_setup(); usart_setup(); USB_setup(); + USBPU_ON(); if(hse) usart_send("Ready @ HSE"); else usart_send("Ready @ HSI"); usart_send(", CFGR="); usart_send(u2hexstr(RCC->CFGR)); @@ -65,7 +67,6 @@ int main(void){ const char *ans = parse_cmd(txt); if(ans) usart_send(ans); } - USB_proc(); int l = USB_receivestr(inbuff, MAXSTRLEN); if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n"); else if(l){ diff --git a/F3:F303/PL2303/openocd.cfg b/F3:F303/PL2303/openocd.cfg index 56ccc2e..0210594 100644 --- a/F3:F303/PL2303/openocd.cfg +++ b/F3:F303/PL2303/openocd.cfg @@ -1,119 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-or-later +set FLASH_SIZE 0x20000 -# script for stm32f3x family - -# -# stm32 devices support both JTAG and SWD transports. -# source [find interface/stlink-v2-1.cfg] -source [find target/swj-dp.tcl] -source [find mem_helper.tcl] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME stm32f3x -} - -set _ENDIAN little - -# Work-area is a space in RAM used for flash programming -# By default use 16kB -if { [info exists WORKAREASIZE] } { - set _WORKAREASIZE $WORKAREASIZE -} else { - set _WORKAREASIZE 0x4000 -} - -# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz -# -# Since we may be running of an RC oscilator, we crank down the speed a -# bit more to be on the safe side. Perhaps superstition, but if are -# running off a crystal, we can run closer to the limit. Note -# that there can be a pretty wide band where things are more or less stable. -adapter speed 1000 - -adapter srst delay 100 -if {[using_jtag]} { - jtag_ntrst_delay 100 -} - -#jtag scan chain -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - if { [using_jtag] } { - # See STM Document RM0316 - # Section 29.6.3 - corresponds to Cortex-M4 r0p1 - set _CPUTAPID 0x4ba00477 - } { - set _CPUTAPID 0x2ba01477 - } -} - -swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID -dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu - -if {[using_jtag]} { - jtag newtap $_CHIPNAME bs -irlen 5 -} - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap - -$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 - -set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME - -reset_config srst_nogate - -if {![using_hla]} { - # if srst is not fitted use SYSRESETREQ to - # perform a soft reset - cortex_m reset_config sysresetreq -} - -proc stm32f3x_default_reset_start {} { - # Reset clock is HSI (8 MHz) - adapter speed 1000 -} - -proc stm32f3x_default_examine_end {} { - # Enable debug during low power modes (uses more power) - mmw 0xe0042004 0x00000007 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP - - # Stop watchdog counters during halt - mmw 0xe0042008 0x00001800 0 ;# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP -} - -proc stm32f3x_default_reset_init {} { - # Configure PLL to boost clock to HSI x 8 (64 MHz) - mww 0x40021004 0x00380400 ;# RCC_CFGR = PLLMUL[3:1] | PPRE1[2] - mmw 0x40021000 0x01000000 0 ;# RCC_CR |= PLLON - mww 0x40022000 0x00000012 ;# FLASH_ACR = PRFTBE | LATENCY[1] - sleep 10 ;# Wait for PLL to lock - mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1] - - # Boost JTAG frequency - adapter speed 8000 -} - -# Default hooks -$_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end } -$_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start } -$_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init } - -tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 - -lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu -proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname} { - targets $_targetname - - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xe0042004 0x00000020 0 -} - -$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME" +source [find target/stm32f3x.cfg] diff --git a/F3:F303/PL2303/pl2303.bin b/F3:F303/PL2303/pl2303.bin index ed169a4..ae0daed 100755 Binary files a/F3:F303/PL2303/pl2303.bin and b/F3:F303/PL2303/pl2303.bin differ diff --git a/F3:F303/PL2303/pl2303.creator.user b/F3:F303/PL2303/pl2303.creator.user index aa79e75..f16c1bd 100644 --- a/F3:F303/PL2303/pl2303.creator.user +++ b/F3:F303/PL2303/pl2303.creator.user @@ -1,10 +1,10 @@ - + EnvironmentId - {7bd84e39-ca37-46d3-be9d-99ebea85bc0d} + {cf63021e-ef53-49b0-b03b-2f2570cdf3b6} ProjectExplorer.Project.ActiveTarget @@ -40,14 +40,14 @@ false true false - 0 + 1 true true 0 8 true false - 1 + 2 true false true @@ -74,7 +74,7 @@ true true Builtin.DefaultTidyAndClazy - 2 + 1 @@ -88,12 +88,12 @@ Desktop Desktop Desktop - {65a14f9e-e008-4c1b-89df-4eaa4774b6e3} + {91347f2c-5221-46a7-80b1-0a054ca02f79} 0 0 0 - /Big/Data/00__Electronics/STM32/F303-nolib/blink + /home/eddy/C-files/stm32samples/F3:F303/PL2303 @@ -125,7 +125,7 @@ false - Default + По умолчанию GenericProjectManager.GenericBuildConfiguration 1 diff --git a/F3:F303/PL2303/proto.c b/F3:F303/PL2303/proto.c index e5e930f..2bac794 100644 --- a/F3:F303/PL2303/proto.c +++ b/F3:F303/PL2303/proto.c @@ -21,7 +21,7 @@ #include "usb.h" #include "version.inc" -uint8_t starttest = 50; +uint8_t starttest = 0; char *omit_spaces(const char *buf){ while(*buf){ diff --git a/F3:F303/PL2303/usart.c b/F3:F303/PL2303/usart.c index 7c03606..1bfcb60 100644 --- a/F3:F303/PL2303/usart.c +++ b/F3:F303/PL2303/usart.c @@ -65,12 +65,6 @@ void usart_send(const char *str){ } void usart_setup(){ - // USART1: Rx - PA10 (AF7), Tx - PA9 (AF7) - // setup pins: - GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER9 | GPIO_MODER_MODER10)) | - GPIO_MODER_MODER9_AF | GPIO_MODER_MODER10_AF; - GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH1 | GPIO_AFRH_AFRH2)) | - 7 << (1 * 4) | 7 << (2 * 4); // PA9, PA10 // clock RCC->APB2ENR |= RCC_APB2ENR_USART1EN; USART1->ICR = 0xffffffff; // clear all flags diff --git a/F3:F303/PL2303/usb.c b/F3:F303/PL2303/usb.c index 79fd7ac..553b6cf 100644 --- a/F3:F303/PL2303/usb.c +++ b/F3:F303/PL2303/usb.c @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -19,23 +19,22 @@ #include #include "hardware.h" -#include "ringbuffer.h" #include "usb.h" #include "usb_lib.h" static volatile uint8_t usbbuff[USB_TXBUFSZ]; // temporary buffer for sending data // ring buffers for incoming and outgoing data static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ]; -static volatile ringbuffer out = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; -static volatile ringbuffer in = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; +volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; +volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; // transmission is succesfull -static volatile uint8_t bufisempty = 1; -static volatile uint8_t bufovrfl = 0; +volatile uint8_t bufisempty = 1; +volatile uint8_t bufovrfl = 0; -static void send_next(){ +void send_next(){ if(bufisempty) return; static int lastdsz = 0; - int buflen = RB_read((ringbuffer*)&out, (uint8_t*)usbbuff, USB_TXBUFSZ); + int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); if(!buflen){ if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send lastdsz = 0; @@ -58,7 +57,7 @@ int USB_sendall(){ int USB_send(const uint8_t *buf, int len){ if(!buf || !usbON || !len) return 0; while(len){ - int a = RB_write((ringbuffer*)&out, buf, len); + int a = RB_write((ringbuffer*)&rbout, buf, len); len -= a; buf += a; if(bufisempty){ @@ -71,7 +70,7 @@ int USB_send(const uint8_t *buf, int len){ int USB_putbyte(uint8_t byte){ if(!usbON) return 0; - while(0 == RB_write((ringbuffer*)&out, &byte, 1)){ + while(0 == RB_write((ringbuffer*)&rbout, &byte, 1)){ if(bufisempty){ bufisempty = 0; send_next(); @@ -96,9 +95,9 @@ int USB_sendstr(const char *string){ * @return amount of received bytes (negative, if overfull happened) */ int USB_receive(uint8_t *buf, int len){ - int sz = RB_read((ringbuffer*)&in, buf, len); + int sz = RB_read((ringbuffer*)&rbin, buf, len); if(bufovrfl){ - RB_clearbuf((ringbuffer*)&in); + RB_clearbuf((ringbuffer*)&rbin); if(!sz) sz = -1; else sz = -sz; bufovrfl = 0; @@ -113,9 +112,9 @@ int USB_receive(uint8_t *buf, int len){ * @return strlen or negative value indicating overflow (if so, string won't be ends with 0 and buffer should be cleared) */ int USB_receivestr(char *buf, int len){ - int l = RB_readto((ringbuffer*)&in, '\n', (uint8_t*)buf, len); + int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len); if(l == 0) return 0; - if(--l < 1 || bufovrfl) RB_clearbuf((ringbuffer*)&in); + if(--l < 0 || bufovrfl) RB_clearbuf((ringbuffer*)&rbin); else buf[l] = 0; // replace '\n' with strend if(bufovrfl){ if(l > 0) l = -l; @@ -125,52 +124,3 @@ int USB_receivestr(char *buf, int len){ return l; } -// interrupt IN handler (never used?) -static void EP1_Handler(){ - uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); - if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX - else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); - // clear CTR - epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); - USB->EPnR[1] = epstatus; -} - -// data IN/OUT handlers -static void transmit_Handler(){ // EP3IN - uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); - // clear CTR keep DTOGs & STATs - USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr - send_next(); -} - -static void receive_Handler(){ // EP2OUT - uint8_t buf[USB_RXBUFSZ]; - uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]); - uint8_t sz = EP_Read(2, (uint16_t*)buf); - if(sz){ - if(RB_write((ringbuffer*)&in, buf, sz) != sz) bufovrfl = 1; - } - // keep stat_tx & set ACK rx, clear RX ctr - USB->EPnR[2] = (epstatus & ~USB_EPnR_CTR_RX) ^ USB_EPnR_STAT_RX; -} - -void USB_proc(){ - switch(USB_Dev.USB_Status){ - case USB_STATE_CONFIGURED: - // make new BULK endpoint - // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features) - EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit - EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data - EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data - USB_Dev.USB_Status = USB_STATE_CONNECTED; - break; - case USB_STATE_DEFAULT: - case USB_STATE_ADDRESSED: - if(usbON){ - usbON = 0; - } - break; - default: // USB_STATE_CONNECTED - send next data portion - if(!usbON) return; - } -} diff --git a/F3:F303/PL2303/usb.h b/F3:F303/PL2303/usb.h index 15d1172..36d0d59 100644 --- a/F3:F303/PL2303/usb.h +++ b/F3:F303/PL2303/usb.h @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -17,22 +17,33 @@ */ #pragma once -#ifndef __USB_H__ -#define __USB_H__ +#include "ringbuffer.h" #include "usbhw.h" // sizes of ringbuffers for outgoing and incoming data #define RBOUTSZ (512) #define RBINSZ (512) -void USB_proc(); +#define newline() USB_putbyte('\n') +#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) + +#define STR_HELPER(s) #s +#define STR(s) STR_HELPER(s) + +#ifdef EBUG +#define DBG(str) do{USB_sendstr(__FILE__ " (L" STR(__LINE__) "): " str); newline();}while(0) +#else +#define DBG(str) +#endif + +extern volatile ringbuffer rbout, rbin; +extern volatile uint8_t bufisempty, bufovrfl; + +void send_next(); int USB_sendall(); int USB_send(const uint8_t *buf, int len); int USB_putbyte(uint8_t byte); int USB_sendstr(const char *string); int USB_receive(uint8_t *buf, int len); int USB_receivestr(char *buf, int len); - - -#endif // __USB_H__ diff --git a/F3:F303/PL2303/usb_lib.c b/F3:F303/PL2303/usb_lib.c index 1df4915..8170040 100644 --- a/F3:F303/PL2303/usb_lib.c +++ b/F3:F303/PL2303/usb_lib.c @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -17,15 +17,16 @@ */ #include +#include "usb.h" #include "usb_lib.h" +#include "usbhw.h" ep_t endpoints[STM32ENDPOINTS]; -usb_dev_t USB_Dev; +static uint16_t USB_Addr = 0; static usb_LineCoding lineCoding = {115200, 0, 0, 8}; -config_pack_t setup_packet; -uint8_t ep0databuf[EP0DATABUF_SIZE]; -uint8_t ep0dbuflen = 0; +uint8_t ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE]; +config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; usb_LineCoding getLineCoding(){return lineCoding;} @@ -54,9 +55,9 @@ static const uint8_t USB_DeviceDescriptor[] = { 0x23, // idProduct_H 0x00, // bcdDevice_Ver_L 0x03, // bcdDevice_Ver_H - 0x01, // iManufacturer - 0x02, // iProduct - 0x00, // iSerialNumber + iMANUFACTURER_DESCR, // iManufacturer + iPRODUCT_DESCR, // iProduct + iSERIAL_DESCR, // iSerialNumber bNumConfigurations // bNumConfigurations }; @@ -96,7 +97,7 @@ static const uint8_t USB_ConfigDescriptor[] = { 0xff, /* bInterfaceClass */ 0x00, /* bInterfaceSubClass */ 0x00, /* bInterfaceProtocol */ - 0x00, /* iInterface: */ + iINTERFACE_DESCR, /* iInterface: */ /////////////////////////////////////////////////// /*Endpoint 1 Descriptor*/ 0x07, /* bLength: Endpoint Descriptor size */ @@ -126,11 +127,19 @@ static const uint8_t USB_ConfigDescriptor[] = { 0x00, /* bInterval: ignore for Bulk transfer */ }; -_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US); -// these descriptors are not used in PL2303 emulator! -_USB_STRING_(USB_StringSerialDescriptor, u"0"); -_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc."); -_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller"); +_USB_LANG_ID_(LD, LANG_US); +_USB_STRING_(SD, u"0.0.1"); +_USB_STRING_(MD, u"Prolific Technology Inc."); +_USB_STRING_(PD, u"USB-Serial Controller"); +_USB_STRING_(ID, u"pl2303_emulator"); +static void const *StringDescriptor[iDESCR_AMOUNT] = { + [iLANGUAGE_DESCR] = &LD, + [iMANUFACTURER_DESCR] = &MD, + [iPRODUCT_DESCR] = &PD, + [iSERIAL_DESCR] = &SD, + [iINTERFACE_DESCR] = &ID +}; + /* * default handlers @@ -172,7 +181,7 @@ void WEAK vendor_handler(config_pack_t *packet){ } static void wr0(const uint8_t *buf, uint16_t size){ - if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request + if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request if(size < endpoints[0].txbufsz){ EP_WriteIRQ(0, buf, size); return; @@ -200,24 +209,18 @@ static void wr0(const uint8_t *buf, uint16_t size){ } static inline void get_descriptor(){ - switch(setup_packet.wValue){ + uint8_t descrtype = setup_packet->wValue >> 8, + descridx = setup_packet->wValue & 0xff; + switch(descrtype){ case DEVICE_DESCRIPTOR: wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor)); break; case CONFIGURATION_DESCRIPTOR: wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor)); break; - case STRING_LANG_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE); - break; - case STRING_MAN_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength); - break; - case STRING_PROD_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength); - break; - case STRING_SN_DESCRIPTOR: - wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength); + case STRING_DESCRIPTOR: + if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx])); + else EP_WriteIRQ(0, (uint8_t*)0, 0); break; case DEVICE_QUALIFIER_DESCRIPTOR: wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); @@ -230,7 +233,7 @@ static inline void get_descriptor(){ static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) static inline void std_d2h_req(){ uint16_t status = 0; // bus powered - switch(setup_packet.bRequest){ + switch(setup_packet->bRequest){ case GET_DESCRIPTOR: get_descriptor(); break; @@ -245,16 +248,47 @@ static inline void std_d2h_req(){ } } +// interrupt IN handler (never used?) +static void EP1_Handler(){ + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX + else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); + // clear CTR + epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); + USB->EPnR[1] = epstatus; +} + +// data IN/OUT handlers +static void transmit_Handler(){ // EP3IN + uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); + // clear CTR keep DTOGs & STATs + USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr + send_next(); +} + +static void receive_Handler(){ // EP2OUT + uint8_t buf[USB_RXBUFSZ]; + uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]); + uint8_t sz = EP_Read(2, (uint8_t*)buf); + if(sz){ + if(RB_write((ringbuffer*)&rbin, buf, sz) != sz) bufovrfl = 1; + } + // keep stat_tx & set ACK rx, clear RX ctr + USB->EPnR[2] = (epstatus & ~USB_EPnR_CTR_RX) ^ USB_EPnR_STAT_RX; +} + static inline void std_h2d_req(){ - switch(setup_packet.bRequest){ + switch(setup_packet->bRequest){ case SET_ADDRESS: // new address will be assigned later - after acknowlegement or request to host - USB_Dev.USB_Addr = setup_packet.wValue; + USB_Addr = setup_packet->wValue; break; case SET_CONFIGURATION: // Now device configured - USB_Dev.USB_Status = USB_STATE_CONFIGURED; - configuration = setup_packet.wValue; + configuration = setup_packet->wValue; + EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit + EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data + EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data break; default: break; @@ -272,8 +306,8 @@ bmRequestType: 76543210 */ void EP0_Handler(){ uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications - uint8_t reqtype = setup_packet.bmRequestType & 0x7f; - uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; + uint8_t reqtype = setup_packet->bmRequestType & 0x7f; + uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; int rxflag = RX_FLAG(epstatus); if(rxflag && SETUP_FLAG(epstatus)){ switch(reqtype){ @@ -286,15 +320,15 @@ void EP0_Handler(){ } break; case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request - if(setup_packet.bRequest == CLEAR_FEATURE){ + if(setup_packet->bRequest == CLEAR_FEATURE){ EP_WriteIRQ(0, (uint8_t *)0, 0); } break; case VENDOR_REQUEST_TYPE: - vendor_handler(&setup_packet); + vendor_handler(setup_packet); break; case CONTROL_REQUEST_TYPE: - switch(setup_packet.bRequest){ + switch(setup_packet->bRequest){ case GET_LINE_CODING: EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding)); break; @@ -302,7 +336,7 @@ void EP0_Handler(){ break; case SET_CONTROL_LINE_STATE: usbON = 1; - clstate_handler(setup_packet.wValue); + clstate_handler(setup_packet->wValue); break; case SEND_BREAK: usbON = 0; @@ -311,23 +345,22 @@ void EP0_Handler(){ default: break; } - if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement + if(setup_packet->bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement break; default: EP_WriteIRQ(0, (uint8_t *)0, 0); } }else if(rxflag){ // got data over EP0 or host acknowlegement if(endpoints[0].rx_cnt){ - if(setup_packet.bRequest == SET_LINE_CODING){ + if(setup_packet->bRequest == SET_LINE_CODING){ linecoding_handler((usb_LineCoding*)ep0databuf); } } } else if(TX_FLAG(epstatus)){ // package transmitted // now we can change address after enumeration - if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ - USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; - // change state to ADRESSED - USB_Dev.USB_Status = USB_STATE_ADDRESSED; + if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){ + USB->DADDR = USB_DADDR_EF | USB_Addr; + usbON = 0; } } epstatus = KEEP_DTOG(USB->EPnR[0]); @@ -344,15 +377,24 @@ void EP0_Handler(){ * @param size - its size */ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ - uint8_t i; if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz; uint16_t N2 = (size + 1) >> 1; // the buffer is 16-bit, so we should copy data as it would be uint16_t uint16_t *buf16 = (uint16_t *)buf; +#if defined USB1_16 + // very bad: what if `size` is odd? uint32_t *out = (uint32_t *)endpoints[number].tx_buf; - for(i = 0; i < N2; ++i, ++out){ + for(int i = 0; i < N2; ++i, ++out){ *out = buf16[i]; } +#elif defined USB2_16 + // use memcpy instead? + for(int i = 0; i < N2; i++){ + endpoints[number].tx_buf[i] = buf16[i]; + } +#else +#error "Define USB1_16 or USB2_16" +#endif USB_BTABLE->EP[number].USB_COUNT_TX = size; } @@ -374,16 +416,23 @@ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ * @param *buf - user array for data * @return amount of data read */ -int EP_Read(uint8_t number, uint16_t *buf){ +int EP_Read(uint8_t number, uint8_t *buf){ int sz = endpoints[number].rx_cnt; if(!sz) return 0; endpoints[number].rx_cnt = 0; +#if defined USB1_16 int n = (sz + 1) >> 1; - uint32_t *in = (uint32_t *)endpoints[number].rx_buf; - if(n){ - for(int i = 0; i < n; ++i, ++in) - buf[i] = *(uint16_t*)in; - } + uint32_t *in = (uint32_t*)endpoints[number].rx_buf; + uint16_t *out = (uint16_t*)buf; + for(int i = 0; i < n; ++i, ++in) + out[i] = *(uint16_t*)in; +#elif defined USB2_16 + // use memcpy instead? + for(int i = 0; i < sz; ++i) + buf[i] = endpoints[number].rx_buf[i]; +#else +#error "Define USB1_16 or USB2_16" +#endif return sz; } diff --git a/F3:F303/PL2303/usb_lib.h b/F3:F303/PL2303/usb_lib.h index b6777b0..09fb6b6 100644 --- a/F3:F303/PL2303/usb_lib.h +++ b/F3:F303/PL2303/usb_lib.h @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -17,8 +17,6 @@ */ #pragma once -#ifndef __USB_LIB_H__ -#define __USB_LIB_H__ #include #include "usbhw.h" @@ -62,14 +60,21 @@ #define CONTROL_DTR 0x01 #define CONTROL_RTS 0x02 -// wValue -#define DEVICE_DESCRIPTOR 0x100 -#define CONFIGURATION_DESCRIPTOR 0x200 -#define STRING_LANG_DESCRIPTOR 0x300 -#define STRING_MAN_DESCRIPTOR 0x301 -#define STRING_PROD_DESCRIPTOR 0x302 -#define STRING_SN_DESCRIPTOR 0x303 -#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 +// string descriptors +enum{ + iLANGUAGE_DESCR, + iMANUFACTURER_DESCR, + iPRODUCT_DESCR, + iSERIAL_DESCR, + iINTERFACE_DESCR, + iDESCR_AMOUNT +}; + +// Types of descriptors +#define DEVICE_DESCRIPTOR 0x01 +#define CONFIGURATION_DESCRIPTOR 0x02 +#define STRING_DESCRIPTOR 0x03 +#define DEVICE_QUALIFIER_DESCRIPTOR 0x06 #define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) #define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) @@ -79,14 +84,6 @@ #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) -// USB state: uninitialized, addressed, ready for use -typedef enum{ - USB_STATE_DEFAULT, - USB_STATE_ADDRESSED, - USB_STATE_CONFIGURED, - USB_STATE_CONNECTED -} USB_state; - // EP types #define EP_TYPE_BULK 0x00 #define EP_TYPE_CONTROL 0x01 @@ -95,6 +92,16 @@ typedef enum{ #define LANG_US (uint16_t)0x0409 +#if 0 +typedef struct{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t *bString; +} string_descriptor_t; + +#define _USB_STRING_(name, str) string_descriptor_t name = {(sizeof(str) + 2), STRING_DESCRIPTOR, str} +#endif + #define _USB_STRING_(name, str) \ static const struct name \ { \ @@ -115,7 +122,6 @@ static const struct name \ \ } \ name = {0x04, 0x03, lng_id} -#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4) // EP0 configuration packet typedef struct { @@ -130,17 +136,11 @@ typedef struct { typedef struct{ uint16_t *tx_buf; // transmission buffer address uint16_t txbufsz; // transmission buffer size - uint16_t *rx_buf; // reception buffer address + uint8_t *rx_buf; // reception buffer address void (*func)(); // endpoint action function unsigned rx_cnt : 10; // received data counter } ep_t; -// USB status & its address -typedef struct { - uint8_t USB_Status; - uint16_t USB_Addr; -}usb_dev_t; - typedef struct { uint32_t dwDTERate; uint8_t bCharFormat; @@ -165,22 +165,18 @@ typedef struct { } __attribute__ ((packed)) usb_cdc_notification; extern ep_t endpoints[]; -extern usb_dev_t USB_Dev; extern volatile uint8_t usbON; -extern config_pack_t setup_packet; -extern uint8_t ep0databuf[]; -extern uint8_t ep0dbuflen; +extern config_pack_t *setup_packet; +extern uint8_t ep0databuf[], setupdatabuf[]; void EP0_Handler(); void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); -int EP_Read(uint8_t number, uint16_t *buf); +int EP_Read(uint8_t number, uint8_t *buf); usb_LineCoding getLineCoding(); void linecoding_handler(usb_LineCoding *lc); void clstate_handler(uint16_t val); void break_handler(); void vendor_handler(config_pack_t *packet); - -#endif // __USB_LIB_H__ diff --git a/F3:F303/PL2303/usbhw.c b/F3:F303/PL2303/usbhw.c index 0afb321..0b812e1 100644 --- a/F3:F303/PL2303/usbhw.c +++ b/F3:F303/PL2303/usbhw.c @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -19,22 +19,12 @@ #include "usb.h" #include "usb_lib.h" +// here we suppose that all PIN settings done in hw_setup earlier void USB_setup(){ NVIC_DisableIRQ(USB_LP_IRQn); // remap USB LP & Wakeup interrupts to 75 and 76 - works only on pure F303 RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // enable tacting of SYSCFG SYSCFG->CFGR1 |= SYSCFG_CFGR1_USB_IT_RMP; - // setup pullup - RCC->AHBENR |= RCC_AHBENR_GPIOAEN; - USBPU_OFF(); - //GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER15_Msk | GPIO_MODER_MODER11_Msk | GPIO_MODER_MODER12_Msk)) | - GPIOA->MODER = (GPIOA->MODER & (MODER_CLR(11) & MODER_CLR(12) & MODER_CLR(15))) | - (MODER_AF(11) | MODER_AF(12) | MODER_O(15)); - //(GPIO_MODER_MODER11_AF | GPIO_MODER_MODER12_AF | GPIO_MODER_MODER15_O); - // USB - alternate function 14 @ pins PA11/PA12 - GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH3_Msk | GPIO_AFRH_AFRH4_Msk)) | - //AFR1(14, 11) | AFR1(14, 12); - AFRf(14, 11) | AFRf(14, 12); RCC->APB1ENR |= RCC_APB1ENR_USBEN; USB->CNTR = USB_CNTR_FRES; // Force USB Reset for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms @@ -45,7 +35,6 @@ void USB_setup(){ USB->ISTR = 0; USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // allow only wakeup & reset interrupts NVIC_EnableIRQ(USB_LP_IRQn); - USBPU_ON(); } static uint16_t lastaddr = LASTADDR_DEFAULT; @@ -72,12 +61,12 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*f countrx = 31 + rxsz / 32; } USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; - endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2); + endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ); endpoints[number].txbufsz = txsz; lastaddr += txsz; USB_BTABLE->EP[number].USB_COUNT_TX = 0; USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; - endpoints[number].rx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2); + endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ); lastaddr += rxsz; USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10; endpoints[number].func = func; @@ -95,7 +84,6 @@ void usb_lp_isr(){ lastaddr = LASTADDR_DEFAULT; // clear address, leave only enable bit USB->DADDR = USB_DADDR_EF; - USB_Dev.USB_Status = USB_STATE_DEFAULT; if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){ return; } @@ -112,12 +100,10 @@ void usb_lp_isr(){ if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit) if(n == 0){ // control endpoint if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack - EP_Read(0, (uint16_t*)&setup_packet); - ep0dbuflen = 0; + EP_Read(0, setupdatabuf); // interrupt handler will be called later }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf - ep0dbuflen = endpoints[0].rx_cnt; - EP_Read(0, (uint16_t*)&ep0databuf); + EP_Read(0, ep0databuf); } } } diff --git a/F3:F303/PL2303/usbhw.h b/F3:F303/PL2303/usbhw.h index 6ba114e..167ec81 100644 --- a/F3:F303/PL2303/usbhw.h +++ b/F3:F303/PL2303/usbhw.h @@ -1,6 +1,6 @@ /* * This file is part of the pl2303 project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 Edward V. Emelianov . * * 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 @@ -17,22 +17,15 @@ */ #pragma once -#ifndef USBHW_H__ -#define USBHW_H__ #include -#define USBPU_port GPIOA -#define USBPU_pin (1<<15) -#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) -#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) - // max endpoints number #define STM32ENDPOINTS 8 /** * Buffers size definition **/ -#define USB_BTABLE_SIZE 512 +#define USB_BTABLE_SIZE 768 // first 64 bytes of USB_BTABLE are registers! //#define USB_EP0_BASEADDR 64 // for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303) @@ -90,18 +83,31 @@ typedef struct { __IO uint32_t BTABLE; } USB_TypeDef; +// F303 D/E have 2x16 access scheme typedef struct{ +#if defined USB2_16 + __IO uint16_t USB_ADDR_TX; + __IO uint16_t USB_COUNT_TX; + __IO uint16_t USB_ADDR_RX; + __IO uint16_t USB_COUNT_RX; +#define ACCESSZ (1) +#define BUFTYPE uint8_t +#elif defined USB1_16 __IO uint32_t USB_ADDR_TX; __IO uint32_t USB_COUNT_TX; __IO uint32_t USB_ADDR_RX; __IO uint32_t USB_COUNT_RX; +#define ACCESSZ (2) +#define BUFTYPE uint16_t +#else +#error "Define USB1_16 or USB2_16" +#endif } USB_EPDATA_TypeDef; + typedef struct{ __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS]; } USB_BtableDef; void USB_setup(); int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()); - -#endif // USBHW_H__ diff --git a/F3:F303/PL2303/version.inc b/F3:F303/PL2303/version.inc index b48b0fa..9e69659 100644 --- a/F3:F303/PL2303/version.inc +++ b/F3:F303/PL2303/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "35" -#define BUILD_DATE "2023-01-22" +#define BUILD_NUMBER "40" +#define BUILD_DATE "2023-04-17" diff --git a/testboard/F0_F1_F3-LQFP48_testboard/stm32.kicad_prl b/testboard/F0_F1_F3-LQFP48_testboard/stm32.kicad_prl index c3177f3..eb0e5ac 100644 --- a/testboard/F0_F1_F3-LQFP48_testboard/stm32.kicad_prl +++ b/testboard/F0_F1_F3-LQFP48_testboard/stm32.kicad_prl @@ -1,7 +1,7 @@ { "board": { "active_layer": 0, - "active_layer_preset": "All Layers", + "active_layer_preset": "All Copper Layers", "auto_track_width": true, "hidden_nets": [], "high_contrast_mode": 0,