fixed USB problem

This commit is contained in:
Edward Emelianov 2024-08-26 20:47:04 +03:00
parent 3e86556206
commit 9166996bff
20 changed files with 326 additions and 240 deletions

View File

@ -390,6 +390,8 @@ Dump command codes. Returns all list of CAN bus command codes.
### dumpconf
Dump current configuration. Returns a lot of information both common (like CAN bus speed, ID and so on) and
for each motor driver. You can call independeng getters for each of this parameter.
### dumpmotN
Dump configuration of Nth motor only.
### dumpmotflags
Dump motor flags' bits (for `motflagsN`) and reaction to limit switches (`eswreact`) values:

View File

@ -20,8 +20,8 @@
#include <stdint.h>
// amount of filter banks in STM32F0
#define STM32F0FBANKNO 28
// amount of filter banks in STM32F
#define STM32FBANKNO 28
// flood period in milliseconds
#define FLOOD_PERIOD_MS 5

View File

@ -200,6 +200,33 @@ int erase_storage(int npage){
return ret;
}
int fn_dumpmot(uint32_t _U_ hash, char _U_ *args){ // "dumpmot" (1224122507)
if(!args || !*args) return RET_WRONGCMD;
uint32_t i;
const char *eq = getnum(args, &i);
if(eq == args || i > STP_STATE_AMOUNT) return RET_WRONGCMD;
char cur = '0' + i;
#define PROPNAME(nm) do{newline(); USB_sendstr(nm); USB_putbyte(cur); USB_putbyte('=');}while(0)
USB_sendstr("microsteps"); USB_putbyte(cur); USB_putbyte('=');
printu(the_conf.microsteps[i]);
PROPNAME("accel");
printu(the_conf.accel[i]);
PROPNAME("maxspeed");
printu(the_conf.maxspd[i]);
PROPNAME("minspeed");
printu(the_conf.minspd[i]);
PROPNAME("maxsteps");
printu(the_conf.maxsteps[i]);
PROPNAME("motcurrent");
printu(the_conf.motcurrent[i]);
PROPNAME("motflags");
printuhex(*((uint8_t*)&the_conf.motflags[i]));
PROPNAME("eswreact");
printu(the_conf.ESW_reaction[i]);
#undef PROPNAME
newline();
return RET_GOOD;
}
int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185)
#ifdef EBUG
@ -212,28 +239,12 @@ int fn_dumpconf(uint32_t _U_ hash, char _U_ *args){ // "dumpconf" (3271513185)
USB_sendstr("\nuserconf_sz="); printu(the_conf.userconf_sz);
USB_sendstr("\ncanspeed="); printu(the_conf.CANspeed);
USB_sendstr("\ncanid="); printu(the_conf.CANID);
newline();
char x[2] = {0};
// motors' data
for(int i = 0; i < MOTORSNO; ++i){
char cur = '0' + i;
#define PROPNAME(nm) do{newline(); USB_sendstr(nm); USB_putbyte(cur); USB_putbyte('=');}while(0)
PROPNAME("microsteps");
printu(the_conf.microsteps[i]);
PROPNAME("accel");
printu(the_conf.accel[i]);
PROPNAME("maxspeed");
printu(the_conf.maxspd[i]);
PROPNAME("minspeed");
printu(the_conf.minspd[i]);
PROPNAME("maxsteps");
printu(the_conf.maxsteps[i]);
PROPNAME("motcurrent");
printu(the_conf.motcurrent[i]);
PROPNAME("motflags");
printuhex(*((uint8_t*)&the_conf.motflags[i]));
PROPNAME("eswreact");
printu(the_conf.ESW_reaction[i]);
#undef PROPNAME
x[0] = '0' + i;
fn_dumpmot(0, x);
}
newline();
return RET_GOOD;
}

View File

@ -56,6 +56,8 @@ int fn_dumpconf(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpconf" (327151318
int fn_dumperr(uint32_t _U_ hash, char _U_ *args) WAL; // "dumperr" (1223989764)
int fn_dumpmot(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpmot" (1224122507)
int fn_dumpmotflags(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpmotflags" (36159640)
int fn_dumpstates(uint32_t _U_ hash, char _U_ *args) WAL; // "dumpstates" (4235564367)
@ -216,6 +218,9 @@ int parsecmd(const char *str){
case CMD_DUMPERR:
return fn_dumperr(h, args);
break;
case CMD_DUMPMOT:
return fn_dumpmot(h, args);
break;
case CMD_DUMPMOTFLAGS:
return fn_dumpmotflags(h, args);
break;

View File

@ -38,6 +38,7 @@ extern char lastcmd[];
#define CMD_DUMPCMD (1223955823)
#define CMD_DUMPCONF (3271513185)
#define CMD_DUMPERR (1223989764)
#define CMD_DUMPMOT (1224122507)
#define CMD_DUMPMOTFLAGS (36159640)
#define CMD_DUMPSTATES (4235564367)
#define CMD_EMSTOP (2965919005)

View File

@ -20,6 +20,7 @@
"dumperr - dump error codes\n"
"dumpcmd - dump command codes\n"
"dumpconf - dump current configuration\n"
"dumpmotN - dump Nth motor configuration\n"
"dumpmotflags - dump motor flags' bits\n"
"dumpstates - dump motors' state codes\n"
"emstop[N] - emergency stop motor N or all\n"

Binary file not shown.

View File

@ -20,6 +20,7 @@ drvtype
dumperr
dumpcmd
dumpconf
dumpmot
dumpmotflags
dumpstates
emstop

View File

@ -45,11 +45,11 @@ int main(void){
hw_setup(); // GPIO, ADC, timers, watchdog etc.
USBPU_OFF(); // make a reconnection
flashstorage_init();
init_steppers();
USB_setup();
CAN_setup(the_conf.CANspeed);
adc_setup();
pdnuart_setup();
init_steppers();
USBPU_ON();
uint32_t ctr = 0;
CAN_message *can_mesg;
@ -60,10 +60,9 @@ int main(void){
LED_blink();
}
CAN_proc();
USB_proc(); // TODO: remove deprecated trash code!
process_steppers();
if(CAN_get_status() == CAN_FIFO_OVERRUN){
USB_sendstr("CAN bus fifo overrun occured!\n");
USB_sendstr("CAN_FIFO_OVERRUN\n");
}
while((can_mesg = CAN_messagebuf_pop())){
if(can_mesg && isgood(can_mesg->ID)){
@ -82,8 +81,13 @@ int main(void){
}
}
int l = USB_receivestr(inbuff, MAXSTRLEN);
if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n");
if(l < 0) USB_sendstr("USB_BUF_OVERFLOW\n");
else if(l){
#ifdef EBUG
USB_sendstr("USB GOT:\n");
USB_sendstr(inbuff);
USB_sendstr("\n--------\n");
#endif
const char *ans = cmd_parser(inbuff);
if(ans) USB_sendstr(ans);
}

View File

@ -205,7 +205,7 @@ static void add_filter(const char *str){
USB_sendstr("No bank# given");
return;
}
if(N > STM32F0FBANKNO-1){
if(N > STM32FBANKNO-1){
USB_sendstr("bank# > 27");
return;
}

View File

@ -18,19 +18,21 @@
#include "ringbuffer.h"
// stored data length
int RB_datalen(ringbuffer *b){
static int datalen(ringbuffer *b){
if(b->tail >= b->head) return (b->tail - b->head);
else return (b->length - b->head + b->tail);
}
/**
* @brief RB_hasbyte - check if buffer has given byte stored
* @param b - buffer
* @param byte - byte to find
* @return index if found, -1 if none
*/
int RB_hasbyte(ringbuffer *b, uint8_t byte){
// stored data length
int RB_datalen(ringbuffer *b){
if(b->busy) return -1;
b->busy = 1;
int l = datalen(b);
b->busy = 0;
return l;
}
static int hasbyte(ringbuffer *b, uint8_t byte){
if(b->head == b->tail) return -1; // no data in buffer
int startidx = b->head;
if(b->head > b->tail){ //
@ -43,6 +45,20 @@ int RB_hasbyte(ringbuffer *b, uint8_t byte){
return -1;
}
/**
* @brief RB_hasbyte - check if buffer has given byte stored
* @param b - buffer
* @param byte - byte to find
* @return index if found, -1 if none or busy
*/
int RB_hasbyte(ringbuffer *b, uint8_t byte){
if(b->busy) return -1;
b->busy = 1;
int ret = hasbyte(b, byte);
b->busy = 0;
return ret;
}
// poor memcpy
static void mcpy(uint8_t *targ, const uint8_t *src, int l){
while(l--) *targ++ = *src++;
@ -54,15 +70,8 @@ TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){
if(*what >= b->length) *what -= b->length;
}
/**
* @brief RB_read - read data from ringbuffer
* @param b - buffer
* @param s - array to write data
* @param len - max len of `s`
* @return bytes read
*/
int RB_read(ringbuffer *b, uint8_t *s, int len){
int l = RB_datalen(b);
static int read(ringbuffer *b, uint8_t *s, int len){
int l = datalen(b);
if(!l) return 0;
if(l > len) l = len;
int _1st = b->length - b->head;
@ -78,33 +87,49 @@ int RB_read(ringbuffer *b, uint8_t *s, int len){
return _1st;
}
/**
* @brief RB_read - read data from ringbuffer
* @param b - buffer
* @param s - array to write data
* @param len - max len of `s`
* @return bytes read or -1 if busy
*/
int RB_read(ringbuffer *b, uint8_t *s, int len){
if(b->busy) return -1;
b->busy = 1;
int r = read(b, s, len);
b->busy = 0;
return r;
}
static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
int idx = hasbyte(b, byte);
if(idx < 0) return 0;
int partlen = idx + 1 - b->head;
// now calculate length of new data portion
if(idx < b->head) partlen += b->length;
if(partlen > len) return -read(b, s, len);
return read(b, s, partlen);
}
/**
* @brief RB_readto fill array `s` with data until byte `byte` (with it)
* @param b - ringbuffer
* @param byte - check byte
* @param s - buffer to write data
* @param len - length of `s`
* @return amount of bytes written (negative, if len<data in buffer)
* @return amount of bytes written (negative, if len<data in buffer or buffer is busy)
*/
int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
int idx = RB_hasbyte(b, byte);
if(idx < 0) return 0;
int partlen = idx + 1 - b->head;
// now calculate length of new data portion
if(idx < b->head) partlen += b->length;
if(partlen > len) return -RB_read(b, s, len);
return RB_read(b, s, partlen);
if(b->busy) return -1;
b->busy = 1;
int n = readto(b, byte, s, len);
b->busy = 0;
return n;
}
/**
* @brief RB_write - write some data to ringbuffer
* @param b - buffer
* @param str - data
* @param l - length
* @return amount of bytes written
*/
int RB_write(ringbuffer *b, const uint8_t *str, int l){
int r = b->length - 1 - RB_datalen(b); // rest length
static int write(ringbuffer *b, const uint8_t *str, int l){
int r = b->length - 1 - datalen(b); // rest length
if(l > r) l = r;
if(!l) return 0;
int _1st = b->length - b->tail;
@ -117,8 +142,27 @@ int RB_write(ringbuffer *b, const uint8_t *str, int l){
return l;
}
/**
* @brief RB_write - write some data to ringbuffer
* @param b - buffer
* @param str - data
* @param l - length
* @return amount of bytes written or -1 if busy
*/
int RB_write(ringbuffer *b, const uint8_t *str, int l){
if(b->busy) return -1;
b->busy = 1;
int w = write(b, str, l);
b->busy = 0;
return w;
}
// just delete all information in buffer `b`
void RB_clearbuf(ringbuffer *b){
int RB_clearbuf(ringbuffer *b){
if(b->busy) return -1;
b->busy = 1;
b->head = 0;
b->tail = 0;
b->busy = 0;
return 1;
}

View File

@ -25,6 +25,7 @@ typedef struct{
const int length; // its length
int head; // head index
int tail; // tail index
volatile int busy; // == TRUE if buffer is busy now
} ringbuffer;
int RB_read(ringbuffer *b, uint8_t *s, int len);
@ -32,4 +33,4 @@ int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len);
int RB_hasbyte(ringbuffer *b, uint8_t byte);
int RB_write(ringbuffer *b, const uint8_t *str, int l);
int RB_datalen(ringbuffer *b);
void RB_clearbuf(ringbuffer *b);
int RB_clearbuf(ringbuffer *b);

View File

@ -1,6 +1,6 @@
/*
* This file is part of the multistepper project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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,27 +19,31 @@
#include <string.h>
#include "hardware.h"
#include "ringbuffer.h"
#include "usb.h"
#include "usb_lib.h"
#ifdef EBUG
#include "strfunc.h"
#endif
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};
// transmission is succesfull
static volatile uint8_t bufisempty = 1;
static volatile uint8_t bufovrfl = 0;
volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0};
volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0};
// inbuf overflow when receiving
volatile uint8_t bufovrfl = 0;
// last send data size
static volatile int lastdsz = 0;
static void send_next(){
if(bufisempty) return;
static int lastdsz = 0;
int buflen = RB_read((ringbuffer*)&out, (uint8_t*)usbbuff, USB_TXBUFSZ);
if(!buflen){
// called from transmit EP
void send_next(){
int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ);
if(buflen == 0){
if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send
lastdsz = 0;
bufisempty = 1;
return;
}else if(buflen < 0){
EP_Write(3, NULL, 0); // send ZLP if buffer is in writting state now
return;
}
EP_Write(3, (uint8_t*)usbbuff, buflen);
@ -48,44 +52,42 @@ static void send_next(){
// blocking send full content of ring buffer
int USB_sendall(){
while(!bufisempty){
if(!usbON) return 0;
while(lastdsz > 0){
if(!usbON) return FALSE;
}
return 1;
return TRUE;
}
// put `buf` into queue to send
int USB_send(const uint8_t *buf, int len){
if(!buf || !usbON || !len) return 0;
if(!buf || !usbON || !len) return FALSE;
while(len){
int a = RB_write((ringbuffer*)&out, buf, len);
len -= a;
buf += a;
if(bufisempty){
bufisempty = 0;
send_next();
}
int a = RB_write((ringbuffer*)&rbout, buf, len);
if(a > 0){
len -= a;
buf += a;
} else if (a < 0) continue; // do nothing if buffer is in reading state
if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN
}
return 1;
return TRUE;
}
int USB_putbyte(uint8_t byte){
if(!usbON) return 0;
while(0 == RB_write((ringbuffer*)&out, &byte, 1)){
if(bufisempty){
bufisempty = 0;
send_next();
}
if(!usbON) return FALSE;
int l = 0;
while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){
if(l < 0) continue;
}
return 1;
if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN
return TRUE;
}
int USB_sendstr(const char *string){
if(!string || !usbON) return 0;
if(!string || !usbON) return FALSE;
int len = 0;
const char *b = string;
while(*b++) ++len;
if(!len) return 0;
if(!len) return FALSE;
return USB_send((const uint8_t*)string, len);
}
@ -96,13 +98,14 @@ 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);
chkin();
if(bufovrfl){
RB_clearbuf((ringbuffer*)&in);
if(!sz) sz = -1;
else sz = -sz;
while(1 != RB_clearbuf((ringbuffer*)&rbin));
bufovrfl = 0;
return -1;
}
int sz = RB_read((ringbuffer*)&rbin, buf, len);
if(sz < 0) return 0; // buffer in writting state
return sz;
}
@ -113,65 +116,25 @@ 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);
if(l == 0) return 0;
if(--l < 0 || bufovrfl) RB_clearbuf((ringbuffer*)&in);
else buf[l] = 0; // replace '\n' with strend
chkin();
if(bufovrfl){
if(l > 0) l = -l;
else l = -1;
while(1 != RB_clearbuf((ringbuffer*)&rbin));
bufovrfl = 0;
return -1;
}
int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len);
if(l < 1){
if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found
while(1 != RB_clearbuf((ringbuffer*)&rbin));
return -1;
}
return 0;
}
#ifdef EBUG
USB_sendstr("readto, l="); USB_sendstr(u2str(l)); newline();
#endif
if(l == 0) return 0;
buf[l-1] = 0; // replace '\n' with strend
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, (uint8_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; // WTF?
break;
}
}

View File

@ -1,6 +1,6 @@
/*
* This file is part of the multistepper project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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
@ -18,11 +18,12 @@
#pragma once
#include "ringbuffer.h"
#include "usbhw.h"
// sizes of ringbuffers for outgoing and incoming data
#define RBOUTSZ (512)
#define RBINSZ (512)
#define RBINSZ (256)
#define newline() USB_putbyte('\n')
#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0)
@ -36,7 +37,10 @@
#define DBG(str)
#endif
void USB_proc();
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);

View File

@ -1,6 +1,6 @@
/*
* This file is part of the multistepper project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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,14 +17,16 @@
*/
#include <stdint.h>
#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 ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE];
config_pack_t *setup_packet = (config_pack_t*) setupdatabuf;
usb_LineCoding getLineCoding(){return lineCoding;}
@ -53,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
};
@ -95,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 */
@ -125,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"multistepper");
static void const *StringDescriptor[iDESCR_AMOUNT] = {
[iLANGUAGE_DESCR] = &LD,
[iMANUFACTURER_DESCR] = &MD,
[iPRODUCT_DESCR] = &PD,
[iSERIAL_DESCR] = &SD,
[iINTERFACE_DESCR] = &ID
};
/*
* default handlers
@ -171,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;
@ -199,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]);
@ -229,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;
@ -244,16 +248,61 @@ 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 uint8_t rcvbuf[USB_RXBUFSZ];
static uint8_t volatile rcvbuflen = 0;
void chkin(){
if(bufovrfl) return;
if(!rcvbuflen) return;
int w = RB_write((ringbuffer*)&rbin, rcvbuf, rcvbuflen);
if(w < 0) return;
if(w != rcvbuflen) bufovrfl = 1;
rcvbuflen = 0;
uint16_t status = KEEP_DTOG(USB->EPnR[2]); // don't change DTOG
USB->EPnR[2] = status ^ USB_EPnR_STAT_RX;
}
// receiver reads data from local buffer and only then ACK'ed
static void receive_Handler(){ // EP2OUT
uint16_t status = KEEP_DTOG_STAT(USB->EPnR[2]); // don't change DTOG and NACK
if(rcvbuflen){
bufovrfl = 1; // lost last data
rcvbuflen = 0;
}
rcvbuflen = EP_Read(2, (uint8_t*)rcvbuf);
USB->EPnR[2] = status & ~USB_EPnR_CTR_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;
@ -271,8 +320,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){
@ -285,15 +334,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;
@ -301,7 +350,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;
@ -310,23 +359,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]);

View File

@ -1,6 +1,6 @@
/*
* This file is part of the multistepper project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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
@ -60,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)
@ -77,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
@ -93,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 \
{ \
@ -113,7 +122,6 @@ static const struct name \
\
} \
name = {0x04, 0x03, lng_id}
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
// EP0 configuration packet
typedef struct {
@ -133,12 +141,6 @@ typedef struct{
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;
@ -163,10 +165,9 @@ 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 config_pack_t *setup_packet;
extern uint8_t ep0databuf[], setupdatabuf[];
void EP0_Handler();
@ -179,3 +180,4 @@ void linecoding_handler(usb_LineCoding *lc);
void clstate_handler(uint16_t val);
void break_handler();
void vendor_handler(config_pack_t *packet);
void chkin();

View File

@ -1,6 +1,6 @@
/*
* This file is part of the multistepper project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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
@ -50,10 +50,10 @@ static uint16_t lastaddr = LASTADDR_DEFAULT;
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){
if(number >= STM32ENDPOINTS) return 4; // out of configured amount
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable
if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE/ACCESSZ) return 2; // out of btable
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size
if(rxsz & 1 || rxsz > USB_BTABLE_SIZE) return 3; // wrong rx buffer size
uint16_t countrx = 0;
if(rxsz < 64) countrx = rxsz / 2;
else{
@ -84,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;
}
@ -101,10 +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, (uint8_t*)&setup_packet);
EP_Read(0, setupdatabuf);
// interrupt handler will be called later
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
EP_Read(0, (uint8_t*)&ep0databuf);
EP_Read(0, ep0databuf);
}
}
}

View File

@ -1,6 +1,6 @@
/*
* This file is part of the multistepper project.
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "119"
#define BUILD_DATE "2024-08-16"
#define BUILD_NUMBER "160"
#define BUILD_DATE "2024-08-26"