Modified F0: testbrd, CDC, pl2303 and HID

This commit is contained in:
eddyem 2020-04-08 14:53:08 +03:00
parent c9b4165645
commit 10ad505bda
68 changed files with 11413 additions and 1233 deletions

View File

@ -25,7 +25,7 @@
#ifndef __USB_DEFS_H__ #ifndef __USB_DEFS_H__
#define __USB_DEFS_H__ #define __USB_DEFS_H__
#include <stm32f0xx.h> #include <stm32f0.h>
/** /**
* Buffers size definition * Buffers size definition

View File

@ -51,7 +51,7 @@ DEPS := $(OBJS:.o=.d)
INC_DIR ?= ../inc INC_DIR ?= ../inc
INCLUDE := -I$(INC_DIR)/F0 -I$(INC_DIR)/cm INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm
LIB_DIR := $(INC_DIR)/ld LIB_DIR := $(INC_DIR)/ld
############################################################################### ###############################################################################

View File

@ -24,7 +24,6 @@
#include "usart.h" #include "usart.h"
#include "usb.h" #include "usb.h"
#include "usb_lib.h" #include "usb_lib.h"
#include <string.h> // memcpy
volatile uint32_t Tms = 0; volatile uint32_t Tms = 0;
@ -56,6 +55,7 @@ void iwdg_setup(){
IWDG->KR = IWDG_REFRESH; /* (6) */ IWDG->KR = IWDG_REFRESH; /* (6) */
} }
#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0)
char *parse_cmd(char *buf){ char *parse_cmd(char *buf){
static char btns[] = "BTN0=0, BTN1=0\n"; static char btns[] = "BTN0=0, BTN1=0\n";
if(buf[1] != '\n') return buf; if(buf[1] != '\n') return buf;
@ -87,17 +87,17 @@ char *parse_cmd(char *buf){
return u2str(getADCval(0)); return u2str(getADCval(0));
break; break;
case 'L': case 'L':
USB_send("Very long test string for USB (it's length is more than 64 bytes).\n" USND("Very long test string for USB (it's length is more than 64 bytes).\n"
"This is another part of the string! Can you see all of this?\n"); "This is another part of the string! Can you see all of this?\n");
return "Long test sent\n"; return "Long test sent\n";
break; break;
case 'R': case 'R':
USB_send("Soft reset\n"); USND("Soft reset\n");
SEND("Soft reset\n"); SEND("Soft reset\n");
NVIC_SystemReset(); NVIC_SystemReset();
break; break;
case 'S': case 'S':
USB_send("Test string for USB\n"); USND("Test string for USB\n");
return "Short test sent\n"; return "Short test sent\n";
break; break;
case 'T': case 'T':
@ -107,7 +107,7 @@ char *parse_cmd(char *buf){
return u2str(getVdd()); return u2str(getVdd());
break; break;
case 'W': case 'W':
USB_send("Wait for reboot\n"); USND("Wait for reboot\n");
SEND("Wait for reboot\n"); SEND("Wait for reboot\n");
while(1){nop();}; while(1){nop();};
break; break;
@ -133,12 +133,9 @@ char *parse_cmd(char *buf){
char *get_USB(){ char *get_USB(){
static char tmpbuf[129], *curptr = tmpbuf; static char tmpbuf[129], *curptr = tmpbuf;
static int rest = 128; static int rest = 128;
int x = USB_receive(curptr, rest); int x = USB_receive((uint8_t*)curptr);
curptr[x] = 0; curptr[x] = 0;
if(!x) return NULL; if(!x) return NULL;
SEND("got: ");
SEND(curptr);
newline();
if(curptr[x-1] == '\n'){ if(curptr[x-1] == '\n'){
curptr = tmpbuf; curptr = tmpbuf;
rest = 128; rest = 128;
@ -187,7 +184,12 @@ int main(void){
SEND("Received data over USB:\n"); SEND("Received data over USB:\n");
SEND(txt); SEND(txt);
newline(); newline();
if(ans) USB_send(ans); if(ans){
uint16_t l = 0; char *p = ans;
while(*p++) l++;
USB_send((uint8_t*)ans, l);
if(ans[l-1] != '\n') USND("\n");
}
} }
if(usartrx()){ // usart1 received data, store in in buffer if(usartrx()){ // usart1 received data, store in in buffer
r = usart_getline(&txt); r = usart_getline(&txt);
@ -202,18 +204,6 @@ int main(void){
} }
// check buttons - each 50ms // check buttons - each 50ms
if(Tms - lastB > 49){ if(Tms - lastB > 49){
/*static uint8_t oldbtn0 = 0, oldbtn1 = 0;
uint8_t btn0 = GET_BTN0(), btn1 = GET_BTN1(), pwm = GET_LED_PWM();
// both: set to middle
if(oldbtn0 != btn0 && oldbtn1 != btn1){
SET_LED_PWM(127);
}else if(oldbtn0 != btn0){ // pressed/released
oldbtn0 = btn0;
if(pwm < 255) SET_LED_PWM(pwm+1);
}else if(oldbtn1 != btn1){
oldbtn1 = btn1;
if(pwm > 0) SET_LED_PWM(pwm-1);
}*/
lastB = Tms; lastB = Tms;
uint8_t btn0 = GET_BTN0(), btn1 = GET_BTN1(), pwm = GET_LED_PWM(); uint8_t btn0 = GET_BTN0(), btn1 = GET_BTN1(), pwm = GET_LED_PWM();
// both: set to middle // both: set to middle

Binary file not shown.

View File

@ -24,52 +24,32 @@
#include "usb.h" #include "usb.h"
#include "usb_lib.h" #include "usb_lib.h"
#include "usart.h" #include "usart.h"
#include <string.h> // memcpy, memmove
// incoming buffer size static volatile uint8_t tx_succesfull = 1;
#define IDATASZ (256) static volatile uint8_t rxNE = 0;
static uint8_t incoming_data[IDATASZ];
static uint8_t ovfl = 0;
static uint16_t idatalen = 0;
static volatile uint8_t tx_succesfull = 0;
static int8_t usbON = 0; // ==1 when USB fully configured
// interrupt IN handler (never used?) // interrupt IN handler (never used?)
static uint16_t EP1_Handler(ep_t ep){ static void EP1_Handler(){
if (ep.rx_flag){ uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
ep.status = SET_VALID_TX(ep.status); if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
ep.status = KEEP_STAT_RX(ep.status); else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
}else if (ep.tx_flag){ // clear CTR
ep.status = SET_VALID_RX(ep.status); epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
ep.status = SET_STALL_TX(ep.status); USB->EPnR[1] = epstatus;
}
return ep.status;
} }
// data IN/OUT handler // data IN/OUT handlers
static uint16_t EP23_Handler(ep_t ep){ static void transmit_Handler(){ // EP3IN
if(ep.rx_flag){
int rd = ep.rx_cnt, rest = IDATASZ - idatalen;
if(rd){
if(rd <= rest){
idatalen += EP_Read(2, &incoming_data[idatalen]);
ovfl = 0;
}else{
ep.status = SET_NAK_RX(ep.status);
ovfl = 1;
return ep.status;
}
}
// end of transaction: clear DTOGs
ep.status = CLEAR_DTOG_RX(ep.status);
ep.status = CLEAR_DTOG_TX(ep.status);
ep.status = SET_STALL_TX(ep.status);
}else if (ep.tx_flag){
ep.status = KEEP_STAT_TX(ep.status);
tx_succesfull = 1; tx_succesfull = 1;
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
} }
ep.status = SET_VALID_RX(ep.status);
return ep.status; static void receive_Handler(){ // EP2OUT
rxNE = 1;
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[2]);
USB->EPnR[2] = (epstatus & ~(USB_EPnR_CTR_RX)); // clear RX ctr
} }
void USB_setup(){ void USB_setup(){
@ -93,66 +73,100 @@ void USB_setup(){
NVIC_EnableIRQ(USB_IRQn); NVIC_EnableIRQ(USB_IRQn);
} }
void usb_proc(){ static int usbwr(const uint8_t *buf, uint16_t l){
if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints uint32_t ctra = 1000000;
if(!usbON){ // endpoints not activated while(--ctra && tx_succesfull == 0){
// make new BULK endpoint IWDG->KR = IWDG_REFRESH;
// 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, 10, 0, EP1_Handler); // IN1 - transmit
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, EP23_Handler); // OUT2 - receive data
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, EP23_Handler); // IN3 - transmit data
usbON = 1;
} }
}else{ tx_succesfull = 0;
usbON = 0; EP_Write(3, buf, l);
ctra = 1000000;
while(--ctra && tx_succesfull == 0){
IWDG->KR = IWDG_REFRESH;
}
if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF?
return 0;
}
static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP)
static uint8_t buflen = 0; // amount of symbols in usbbuff
// send next up to 63 bytes of data in usbbuff
static void send_next(){
if(!buflen || !tx_succesfull) return;
tx_succesfull = 0;
EP_Write(3, usbbuff, buflen);
buflen = 0;
}
// unblocking sending - just fill a buffer
void USB_send(const uint8_t *buf, uint16_t len){
if(!usbON || !len) return;
if(len > USB_TXBUFSZ-1 - buflen){
usbwr(usbbuff, buflen);
buflen = 0;
}
if(len > USB_TXBUFSZ-1){
USB_send_blk(buf, len);
return;
}
while(len--) usbbuff[buflen++] = *buf++;
}
// blocking sending
void USB_send_blk(const uint8_t *buf, uint16_t len){
if(!usbON || !len) return; // USB disconnected
if(buflen){
usbwr(usbbuff, buflen);
buflen = 0;
}
int needzlp = 0;
while(len){
if(len == USB_TXBUFSZ) needzlp = 1;
uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len;
if(usbwr(buf, s)) return;
len -= s;
buf += s;
}
if(needzlp){
usbwr(NULL, 0);
} }
} }
void USB_send(char *buf){ void usb_proc(){
uint16_t l = 0, ctr = 0; switch(USB_Dev.USB_Status){
char *p = buf; case USB_STATE_CONFIGURED:
while(*p++) ++l; // make new BULK endpoint
while(l){ // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l; EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit
tx_succesfull = 0; EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data
EP_Write(3, (uint8_t*)&buf[ctr], s); EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data
uint32_t ctra = 1000000; USB_Dev.USB_Status = USB_STATE_CONNECTED;
while(--ctra && tx_succesfull == 0); break;
l -= s; case USB_STATE_DEFAULT:
ctr += s; case USB_STATE_ADDRESSED:
if(usbON){
usbON = 0;
}
break;
default: // USB_STATE_CONNECTED - send next data portion
if(!usbON) return;
send_next();
} }
} }
/** /**
* @brief USB_receive * @brief USB_receive
* @param buf (i) - buffer for received data * @param buf (i) - buffer[64] for received data
* @param bufsize - its size
* @return amount of received bytes * @return amount of received bytes
*/ */
int USB_receive(char *buf, int bufsize){ uint8_t USB_receive(uint8_t *buf){
if(!bufsize || !idatalen) return 0; if(!usbON || !rxNE) return 0;
USB->CNTR = 0; SEND((char*)buf); newline();
int sz = (idatalen > bufsize) ? bufsize : idatalen, rest = idatalen - sz; uint8_t sz = EP_Read(2, buf);
memcpy(buf, incoming_data, sz); uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]);
if(rest > 0){ // keep stat_tx & set ACK rx
memmove(incoming_data, &incoming_data[sz], rest); USB->EPnR[2] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
idatalen = rest; rxNE = 0;
}else idatalen = 0;
if(ovfl){
EP23_Handler(endpoints[2]);
uint16_t epstatus = USB->EPnR[2];
epstatus = CLEAR_DTOG_RX(epstatus);
epstatus = SET_VALID_RX(epstatus);
USB->EPnR[2] = epstatus;
}
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
return sz; return sz;
} }
/**
* @brief USB_configured
* @return 1 if USB is in configured state
*/
int USB_configured(){
return usbON;
}

View File

@ -30,8 +30,8 @@
void USB_setup(); void USB_setup();
void usb_proc(); void usb_proc();
void USB_send(char *buf); void USB_send(const uint8_t *buf, uint16_t len);
int USB_receive(char *buf, int bufsize); void USB_send_blk(const uint8_t *buf, uint16_t len);
int USB_configured(); uint8_t USB_receive(uint8_t *buf);
#endif // __USB_H__ #endif // __USB_H__

View File

@ -25,7 +25,11 @@
#ifndef __USB_DEFS_H__ #ifndef __USB_DEFS_H__
#define __USB_DEFS_H__ #define __USB_DEFS_H__
#include <stm32f0xx.h> #include <stm32f0.h>
// max endpoints number
#define STM32ENDPOINTS 8
#define USB_EP1BUFSZ 8
/** /**
* Buffers size definition * Buffers size definition
@ -74,15 +78,8 @@
#define USB_TypeDef USB_TypeDef_custom #define USB_TypeDef USB_TypeDef_custom
typedef struct{ typedef struct{
__IO uint32_t EPnR[8]; __IO uint32_t EPnR[STM32ENDPOINTS];
__IO uint32_t RESERVED1; __IO uint32_t RESERVED[STM32ENDPOINTS];
__IO uint32_t RESERVED2;
__IO uint32_t RESERVED3;
__IO uint32_t RESERVED4;
__IO uint32_t RESERVED5;
__IO uint32_t RESERVED6;
__IO uint32_t RESERVED7;
__IO uint32_t RESERVED8;
__IO uint32_t CNTR; __IO uint32_t CNTR;
__IO uint32_t ISTR; __IO uint32_t ISTR;
__IO uint32_t FNR; __IO uint32_t FNR;
@ -100,7 +97,7 @@ typedef struct{
} USB_EPDATA_TypeDef; } USB_EPDATA_TypeDef;
typedef struct{ typedef struct{
__IO USB_EPDATA_TypeDef EP[8]; __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
} USB_BtableDef; } USB_BtableDef;
#endif // __USB_DEFS_H__ #endif // __USB_DEFS_H__

View File

@ -22,13 +22,15 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include "usb_lib.h"
#include <string.h> // memcpy
#include "usart.h" #include "usart.h"
#include "usb_lib.h"
ep_t endpoints[ENDPOINTS_NUM];
static usb_dev_t USB_Dev; ep_t endpoints[STM32ENDPOINTS];
usb_dev_t USB_Dev;
uint8_t usbON = 0; // device disconnected from terminal
static usb_LineCoding lineCoding = {115200, 0, 0, 8}; static usb_LineCoding lineCoding = {115200, 0, 0, 8};
static config_pack_t setup_packet; static config_pack_t setup_packet;
static uint8_t ep0databuf[EP0DATABUF_SIZE]; static uint8_t ep0databuf[EP0DATABUF_SIZE];
@ -176,8 +178,31 @@ void WEAK vendor_handler(config_pack_t *packet){
} }
static void wr0(const uint8_t *buf, uint16_t size){ static void wr0(const uint8_t *buf, uint16_t size){
if(setup_packet.wLength < size) size = setup_packet.wLength; if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
if(size < endpoints[0].txbufsz){
EP_WriteIRQ(0, buf, size); EP_WriteIRQ(0, buf, size);
return;
}
while(size){
uint16_t l = size;
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
EP_WriteIRQ(0, buf, l);
buf += l;
size -= l;
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
if(size || needzlp){ // send last data buffer
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
^ USB_EPnR_STAT_TX;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
if((USB->ISTR & USB_ISTR_CTR) == 0){
return;
}
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
}
}
} }
static inline void get_descriptor(){ static inline void get_descriptor(){
@ -234,7 +259,7 @@ static inline void std_h2d_req(){
break; break;
case SET_CONFIGURATION: case SET_CONFIGURATION:
// Now device configured // Now device configured
USB_Dev.USB_Status = USB_CONFIGURE_STATE; USB_Dev.USB_Status = USB_STATE_CONFIGURED;
configuration = setup_packet.wValue; configuration = setup_packet.wValue;
break; break;
default: default:
@ -250,38 +275,29 @@ bmRequestType: 76543210
*/ */
/** /**
* Endpoint0 (control) handler * Endpoint0 (control) handler
* @param ep - endpoint state
* @return data written to EP0R
*/ */
static uint16_t EP0_Handler(ep_t ep){ static void EP0_Handler(){
uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications
uint8_t reqtype = setup_packet.bmRequestType & 0x7f; uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
if ((ep.rx_flag) && (ep.setup_flag)){ int rxflag = RX_FLAG(epstatus);
if(rxflag && SETUP_FLAG(epstatus)){
switch(reqtype){ switch(reqtype){
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
if(dev2host){ if(dev2host){
std_d2h_req(); std_d2h_req();
}else{ }else{
std_h2d_req(); std_h2d_req();
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
} }
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
if(setup_packet.bRequest == CLEAR_FEATURE){ if(setup_packet.bRequest == CLEAR_FEATURE){
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} }
break; break;
case VENDOR_REQUEST_TYPE: case VENDOR_REQUEST_TYPE:
vendor_handler(&setup_packet); vendor_handler(&setup_packet);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
case CONTROL_REQUEST_TYPE: case CONTROL_REQUEST_TYPE:
switch(setup_packet.bRequest){ switch(setup_packet.bRequest){
@ -291,47 +307,40 @@ static uint16_t EP0_Handler(ep_t ep){
case SET_LINE_CODING: // omit this for next stage, when data will come case SET_LINE_CODING: // omit this for next stage, when data will come
break; break;
case SET_CONTROL_LINE_STATE: case SET_CONTROL_LINE_STATE:
usbON = 1;
clstate_handler(setup_packet.wValue); clstate_handler(setup_packet.wValue);
break; break;
case SEND_BREAK: case SEND_BREAK:
usbON = 0;
break_handler(); break_handler();
break; break;
default: default:
break; break;
} }
if(!dev2host) 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
epstatus = SET_VALID_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
default: default:
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} }
}else if (ep.rx_flag){ // got data over EP0 or host acknowlegement }else if(rxflag){ // got data over EP0 or host acknowlegement
if(ep.rx_cnt){ if(endpoints[0].rx_cnt){
//EP_WriteIRQ(0, (uint8_t *)0, 0);
if(setup_packet.bRequest == SET_LINE_CODING){ if(setup_packet.bRequest == SET_LINE_CODING){
linecoding_handler((usb_LineCoding*)ep0databuf); linecoding_handler((usb_LineCoding*)ep0databuf);
} }
} }
// wait for new data from host } else if(TX_FLAG(epstatus)){ // package transmitted
epstatus = SET_VALID_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} else if (ep.tx_flag){ // package transmitted
// now we can change address after enumeration // now we can change address after enumeration
if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
// change state to ADRESSED // change state to ADRESSED
USB_Dev.USB_Status = USB_ADRESSED_STATE; USB_Dev.USB_Status = USB_STATE_ADDRESSED;
} }
// end of transaction
epstatus = CLEAR_DTOG_RX(epstatus);
epstatus = CLEAR_DTOG_TX(epstatus);
epstatus = SET_VALID_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} }
return epstatus; epstatus = KEEP_DTOG(USB->EPnR[0]);
if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
// keep DTOGs, clear CTR_RX,TX, set RX VALID
USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
} }
static uint16_t lastaddr = USB_EP0_BASEADDR; static uint16_t lastaddr = USB_EP0_BASEADDR;
@ -345,8 +354,8 @@ static uint16_t lastaddr = USB_EP0_BASEADDR;
* @param uint16_t (*func)(ep_t *ep) - EP handler function * @param uint16_t (*func)(ep_t *ep) - EP handler function
* @return 0 if all OK * @return 0 if all OK
*/ */
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)){ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()){
if(number >= ENDPOINTS_NUM) return 4; // out of configured amount if(number >= STM32ENDPOINTS) return 4; // out of configured amount
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large 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) return 2; // out of btable
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
@ -360,6 +369,7 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t
} }
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr); endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr);
endpoints[number].txbufsz = txsz;
lastaddr += txsz; lastaddr += txsz;
USB_BTABLE->EP[number].USB_COUNT_TX = 0; USB_BTABLE->EP[number].USB_COUNT_TX = 0;
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
@ -374,56 +384,43 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t
// standard IRQ handler // standard IRQ handler
void usb_isr(){ void usb_isr(){
if (USB->ISTR & USB_ISTR_RESET){ if (USB->ISTR & USB_ISTR_RESET){
usbON = 0;
// Reinit registers // Reinit registers
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
USB->ISTR = 0; USB->ISTR = 0;
// Endpoint 0 - CONTROL // Endpoint 0 - CONTROL
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
lastaddr = USB_EP0_BASEADDR; // roll back to beginning of buffer lastaddr = LASTADDR_DEFAULT; // roll back to beginning of buffer
EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler); EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler);
// clear address, leave only enable bit // clear address, leave only enable bit
USB->DADDR = USB_DADDR_EF; USB->DADDR = USB_DADDR_EF;
// state is default - wait for enumeration // state is default - wait for enumeration
USB_Dev.USB_Status = USB_DEFAULT_STATE; USB_Dev.USB_Status = USB_STATE_DEFAULT;
} }
if(USB->ISTR & USB_ISTR_CTR){ if(USB->ISTR & USB_ISTR_CTR){
// EP number // EP number
uint8_t n = USB->ISTR & USB_ISTR_EPID; uint8_t n = USB->ISTR & USB_ISTR_EPID;
// copy status register // copy status register
uint16_t epstatus = USB->EPnR[n]; uint16_t epstatus = USB->EPnR[n];
// Calculate flags
endpoints[n].rx_flag = (epstatus & USB_EPnR_CTR_RX) ? 1 : 0;
endpoints[n].setup_flag = (epstatus & USB_EPnR_SETUP) ? 1 : 0;
endpoints[n].tx_flag = (epstatus & USB_EPnR_CTR_TX) ? 1 : 0;
// copy received bytes amount // copy received bytes amount
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
// check direction // check direction
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(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(n == 0){ // control endpoint
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(setup_packet)); EP_Read(0, (uint8_t*)&setup_packet);
ep0dbuflen = 0; ep0dbuflen = 0;
// interrupt handler will be called later // interrupt handler will be called later
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
ep0dbuflen = endpoints[0].rx_cnt; ep0dbuflen = endpoints[0].rx_cnt;
memcpy(ep0databuf, endpoints[0].rx_buf, ep0dbuflen); EP_Read(0, (uint8_t*)&ep0databuf);
} }
} }
}else{ // IN interrupt - transmit data, only CTR_TX == 1 }else{ // IN interrupt - transmit data, only CTR_TX == 1
// enumeration end could be here (if EP0) // enumeration end could be here (if EP0)
} }
// prepare status field for EP handler // call EP handler
endpoints[n].status = epstatus; if(endpoints[n].func) endpoints[n].func(endpoints[n]);
// call EP handler (even if it will change EPnR, it should return new status)
epstatus = endpoints[n].func(endpoints[n]);
// keep DTOG state
epstatus = KEEP_DTOG_TX(epstatus);
epstatus = KEEP_DTOG_RX(epstatus);
// clear all RX/TX flags
epstatus = CLEAR_CTR_RX(epstatus);
epstatus = CLEAR_CTR_TX(epstatus);
// refresh EPnR
USB->EPnR[n] = epstatus;
} }
} }
@ -435,7 +432,7 @@ void usb_isr(){
*/ */
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
uint8_t i; uint8_t i;
if(size > USB_TXBUFSZ) size = USB_TXBUFSZ; if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz;
uint16_t N2 = (size + 1) >> 1; uint16_t N2 = (size + 1) >> 1;
// the buffer is 16-bit, so we should copy data as it would be uint16_t // the buffer is 16-bit, so we should copy data as it would be uint16_t
uint16_t *buf16 = (uint16_t *)buf; uint16_t *buf16 = (uint16_t *)buf;
@ -452,13 +449,10 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
* @param size - its size * @param size - its size
*/ */
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
uint16_t status = USB->EPnR[number];
EP_WriteIRQ(number, buf, size); EP_WriteIRQ(number, buf, size);
status = SET_NAK_RX(status); uint16_t status = KEEP_DTOG(USB->EPnR[number]);
status = SET_VALID_TX(status); // keep DTOGs, clear CTR_TX & set TX VALID to start transmission
status = KEEP_DTOG_TX(status); USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
status = KEEP_DTOG_RX(status);
USB->EPnR[number] = status;
} }
/* /*
@ -468,14 +462,10 @@ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
*/ */
int EP_Read(uint8_t number, uint8_t *buf){ int EP_Read(uint8_t number, uint8_t *buf){
int n = endpoints[number].rx_cnt; int n = endpoints[number].rx_cnt;
endpoints[number].rx_cnt = 0;
if(n){ if(n){
for(int i = 0; i < n; ++i) for(int i = 0; i < n; ++i)
buf[i] = endpoints[number].rx_buf[i]; buf[i] = endpoints[number].rx_buf[i];
} }
return n; return n;
} }
// USB status
uint8_t USB_GetState(){
return USB_Dev.USB_Status;
}

View File

@ -29,6 +29,7 @@
#include "usb_defs.h" #include "usb_defs.h"
#define EP0DATABUF_SIZE (64) #define EP0DATABUF_SIZE (64)
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
// Max EP amount (EP0 + other used) // Max EP amount (EP0 + other used)
#define ENDPOINTS_NUM 4 #define ENDPOINTS_NUM 4
@ -77,31 +78,21 @@
#define STRING_SN_DESCRIPTOR 0x303 #define STRING_SN_DESCRIPTOR 0x303
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 #define DEVICE_QUALIFIER_DESCRIPTOR 0x600
// EPnR bits manipulation #define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) #define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R #define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX)
#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX))
#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX))
#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R
#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX)
#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX))
#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX))
#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX))
#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX))
#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX))
#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX))
#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX))
#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX))
#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX))
#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX))
#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX))
#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX)))
// USB state: uninitialized, addressed, ready for use // EPnR bits manipulation
#define USB_DEFAULT_STATE 0 #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define USB_ADRESSED_STATE 1 #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define USB_CONFIGURE_STATE 2
// USB state: uninitialized, addressed, ready for use, connected
typedef enum{
USB_STATE_DEFAULT,
USB_STATE_ADDRESSED,
USB_STATE_CONFIGURED,
USB_STATE_CONNECTED
} USB_state;
// EP types // EP types
#define EP_TYPE_BULK 0x00 #define EP_TYPE_BULK 0x00
@ -143,15 +134,12 @@ typedef struct {
} config_pack_t; } config_pack_t;
// endpoints state // endpoints state
typedef struct __ep_t{ typedef struct{
uint16_t *tx_buf; // transmission buffer address uint16_t *tx_buf; // transmission buffer address
uint16_t txbufsz; // transmission buffer size
uint8_t *rx_buf; // reception buffer address uint8_t *rx_buf; // reception buffer address
uint16_t (*func)(); // endpoint action function void (*func)(); // endpoint action function
uint16_t status; // status flags
unsigned rx_cnt : 10; // received data counter unsigned rx_cnt : 10; // received data counter
unsigned tx_flag : 1; // transmission flag
unsigned rx_flag : 1; // reception flag
unsigned setup_flag : 1; // this is setup packet (only for EP0)
} ep_t; } ep_t;
// USB status & its address // USB status & its address
@ -184,19 +172,20 @@ typedef struct {
} __attribute__ ((packed)) usb_cdc_notification; } __attribute__ ((packed)) usb_cdc_notification;
extern ep_t endpoints[]; extern ep_t endpoints[];
extern usb_dev_t USB_Dev;
extern uint8_t usbON;
void USB_Init(); void USB_Init();
uint8_t USB_GetState(); int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep));
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); 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); void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
int EP_Read(uint8_t number, uint8_t *buf); int EP_Read(uint8_t number, uint8_t *buf);
usb_LineCoding getLineCoding(); usb_LineCoding getLineCoding();
void WEAK linecoding_handler(usb_LineCoding *lc); void linecoding_handler(usb_LineCoding *lc);
void WEAK clstate_handler(uint16_t val); void clstate_handler(uint16_t val);
void WEAK break_handler(); void break_handler();
void WEAK vendor_handler(config_pack_t *packet); void vendor_handler(config_pack_t *packet);
#endif // __USB_LIB_H__ #endif // __USB_LIB_H__

Binary file not shown.

View File

@ -107,25 +107,12 @@ int main(void){
USB_setup(); USB_setup();
iwdg_setup(); iwdg_setup();
//int N = 0;
while (1){ while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(lastT > Tms || Tms - lastT > 499){ if(lastT > Tms || Tms - lastT > 499){
LED_blink(LED0); LED_blink(LED0);
lastT = Tms; lastT = Tms;
transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s
/*if(N){
SEND("start: ");
printu(Tms);
for(int i = 0; i < 100; ++i){
IWDG->KR = IWDG_REFRESH;
send_word("0123456789abcdefghi\n");
}
SEND("stop: ");
printu(Tms);
newline();
--N;
}*/
} }
usb_proc(); usb_proc();
if(usartrx()){ // usart1 received data, store in in buffer if(usartrx()){ // usart1 received data, store in in buffer
@ -136,12 +123,11 @@ int main(void){
switch(_1st){ switch(_1st){
case 'C': case 'C':
SEND("USB "); SEND("USB ");
if(!USB_configured()) SEND("dis"); if(!usbON) SEND("dis");
SEND("connected\n"); SEND("connected\n");
break; break;
case 'K': case 'K':
send_word("Hello, weird and cruel world!\n\n"); send_word("Hello, weird and cruel world!\n\n");
//N = 2;
SEND("Write hello\n"); SEND("Write hello\n");
break; break;
case 'M': case 'M':
@ -168,13 +154,13 @@ int main(void){
break; break;
} }
} }
transmit_tbuf();
}
if(L){ // echo all other data if(L){ // echo all other data
txt[L] = 0; txt[L] = 0;
usart_send(txt); usart_send(txt);
L = 0; L = 0;
} }
transmit_tbuf();
}
} }
return 0; return 0;
} }

View File

@ -25,47 +25,19 @@
#include "usb.h" #include "usb.h"
#include "usb_lib.h" #include "usb_lib.h"
#include "usart.h" #include "usart.h"
#include <string.h> // memcpy, memmove
static int8_t usbON = 0; // ==1 when USB fully configured static volatile uint8_t tx_succesfull = 1;
static volatile uint8_t tx_succesfull = 0; static void EP1_Handler(){
uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
static uint16_t EP1_Handler(ep_t ep){ if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
/*if (ep.rx_flag){ else{
MSG("EP1 OUT: ");
#ifdef EBUG
printu(ep.rx_cnt);
newline();
#endif
uint8_t epbuf[10];
EP_Read(1, epbuf);
ep.status = SET_VALID_TX(ep.status);
ep.status = KEEP_STAT_RX(ep.status);
}else */
if (ep.tx_flag){
MSG("EP1 IN: ");
#ifdef EBUG
printu(ep.rx_cnt);
newline();
#endif
tx_succesfull = 1; tx_succesfull = 1;
ep.status = SET_VALID_RX(ep.status); epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
ep.status = SET_VALID_TX(ep.status);
} }
return ep.status; // clear CTR
} epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
USB->EPnR[1] = epstatus;
/**
* @brief EP_WaitTransmission - wait until data transmitted (or timeout)
* @param number - EP number
* @return 0 if all OK, 1 if timed out
*/
static uint8_t EP_WaitTransmission(){
uint32_t ctr = 1000000;
while(--ctr && tx_succesfull == 0);
if(!tx_succesfull) return 1;
return 0;
} }
void USB_setup(){ void USB_setup(){
@ -90,9 +62,8 @@ void USB_setup(){
} }
void usb_proc(){ void usb_proc(){
if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints if(USB_Dev.USB_Status == USB_STATE_CONFIGURED){ // USB configured - activate other endpoints
if(!usbON){ // endpoints not activated if(!usbON){ // endpoints not activated
SEND("Configure endpoints\n");
EP_Init(1, EP_TYPE_INTERRUPT, USB_TXBUFSZ, 0, EP1_Handler); // IN1 - transmit EP_Init(1, EP_TYPE_INTERRUPT, USB_TXBUFSZ, 0, EP1_Handler); // IN1 - transmit
usbON = 1; usbON = 1;
} }
@ -102,21 +73,18 @@ void usb_proc(){
} }
void USB_send(uint8_t *buf, uint16_t size){ void USB_send(uint8_t *buf, uint16_t size){
if(!usbON) return;
uint16_t ctr = 0; uint16_t ctr = 0;
while(size){ while(size){
uint16_t s = (size > USB_KEYBOARD_REPORT_SIZE) ? USB_KEYBOARD_REPORT_SIZE : size; uint16_t s = (size > USB_KEYBOARD_REPORT_SIZE) ? USB_KEYBOARD_REPORT_SIZE : size;
tx_succesfull = 0; tx_succesfull = 0;
EP_Write(1, (uint8_t*)&buf[ctr], s); EP_Write(1, (uint8_t*)&buf[ctr], s);
if(EP_WaitTransmission()) SEND("Err\n"); uint32_t ctra = 1000000;
while(--ctra && tx_succesfull == 0){
IWDG->KR = IWDG_REFRESH;
}
if(!tx_succesfull) return;
size -= s; size -= s;
ctr += s; ctr += s;
} }
} }
/**
* @brief USB_configured
* @return 1 if USB is in configured state
*/
int USB_configured(){
return usbON;
}

View File

@ -31,6 +31,5 @@
void USB_setup(); void USB_setup();
void usb_proc(); void usb_proc();
void USB_send(uint8_t *buf, uint16_t size); void USB_send(uint8_t *buf, uint16_t size);
int USB_configured();
#endif // __USB_H__ #endif // __USB_H__

View File

@ -25,15 +25,16 @@
#ifndef __USB_DEFS_H__ #ifndef __USB_DEFS_H__
#define __USB_DEFS_H__ #define __USB_DEFS_H__
#include <stm32f0xx.h> #include <stm32f0.h>
// max endpoints number
#define STM32ENDPOINTS 8
/** /**
* Buffers size definition * Buffers size definition
**/ **/
// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! // !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
#define USB_BTABLE_SIZE 1024 #define USB_BTABLE_SIZE 1024
// 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) // for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
#define USB_EP0_BUFSZ 64 #define USB_EP0_BUFSZ 64
// USB transmit buffer size (larger than keyboard report to prevent need of ZLP!) // USB transmit buffer size (larger than keyboard report to prevent need of ZLP!)
@ -72,15 +73,8 @@
#define USB_TypeDef USB_TypeDef_custom #define USB_TypeDef USB_TypeDef_custom
typedef struct{ typedef struct{
__IO uint32_t EPnR[8]; __IO uint32_t EPnR[STM32ENDPOINTS];
__IO uint32_t RESERVED1; __IO uint32_t RESERVED[STM32ENDPOINTS];
__IO uint32_t RESERVED2;
__IO uint32_t RESERVED3;
__IO uint32_t RESERVED4;
__IO uint32_t RESERVED5;
__IO uint32_t RESERVED6;
__IO uint32_t RESERVED7;
__IO uint32_t RESERVED8;
__IO uint32_t CNTR; __IO uint32_t CNTR;
__IO uint32_t ISTR; __IO uint32_t ISTR;
__IO uint32_t FNR; __IO uint32_t FNR;
@ -98,7 +92,7 @@ typedef struct{
} USB_EPDATA_TypeDef; } USB_EPDATA_TypeDef;
typedef struct{ typedef struct{
__IO USB_EPDATA_TypeDef EP[8]; __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
} USB_BtableDef; } USB_BtableDef;
#endif // __USB_DEFS_H__ #endif // __USB_DEFS_H__

View File

@ -23,19 +23,13 @@
#include <stdint.h> #include <stdint.h>
#include "usb_lib.h" #include "usb_lib.h"
#include <string.h> // memcpy
#include "usart.h" #include "usart.h"
static ep_t endpoints[ENDPOINTS_NUM]; ep_t endpoints[STM32ENDPOINTS];
//static uint8_t set_featuring; usb_dev_t USB_Dev;
static usb_dev_t USB_Dev;
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
static config_pack_t setup_packet; static config_pack_t setup_packet;
static uint8_t ep0databuf[EP0DATABUF_SIZE]; uint8_t usbON = 0;
static uint8_t ep0dbuflen = 0;
usb_LineCoding getLineCoding(){return lineCoding;}
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor // definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
#define bcdUSB_L 0x00 #define bcdUSB_L 0x00
@ -141,50 +135,6 @@ static const uint8_t HID_ReportDescriptor[] = {
0xC0 /* End Collection,End Collection */ 0xC0 /* End Collection,End Collection */
}; };
#if 0
const uint8_t HID_ReportDescriptor[] = {
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xA1, 0x01, /* Collection (Application) */
0x05, 0x07, /* Usage (Key codes) */
0x19, 0xE0, /* Usage Minimum (224) */
0x29, 0xE7, /* Usage Maximum (231) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x08, /* Report Count (8) */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x08, /* Report Size (8) */
0x81, 0x01, /* Input (Constant) ;5 bit padding */
0x95, 0x05, /* Report Count (5) */
0x75, 0x01, /* Report Size (1) */
0x05, 0x08, /* Usage Page (Page# for LEDs) */
0x19, 0x01, /* Usage Minimum (01) */
0x29, 0x05, /* Usage Maximum (05) */
0x91, 0x02, /* Output (Data, Variable, Absolute) */
0x95, 0x01, /* Report Count (1) */
0x75, 0x03, /* Report Size (3) */
0x91, 0x01, /* Output (Constant) */
0x95, 0x06, /* Report Count (1) */
0x75, 0x08, /* Report Size (3) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x65, /* Logical Maximum (101) */
0x05, 0x07, /* Usage (Key codes) */
0x19, 0x00, /* Usage Minimum (00) */
0x29, 0x65, /* Usage Maximum (101) */
0x81, 0x00, /* Input (Data, Array) */
0x09, 0x05, /* Usage (Vendor Defined) */
0x15, 0x00, /* Logical Minimum (0)) */
0x26, 0xFF, 0x00, /* Logical Maximum (255)) */
0x75, 0x08, /* Report Count (2)) */
0x95, 0x02, /* Report Size (8 bit)) */
0xB1, 0x02, /* Feature (Data, Variable, Absolute) */
0xC0 /* End Collection,End Collection */
};
#endif
static const uint8_t USB_ConfigDescriptor[] = { static const uint8_t USB_ConfigDescriptor[] = {
/*Configuration Descriptor*/ /*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */ 0x09, /* bLength: Configuration Descriptor size */
@ -228,53 +178,62 @@ static const uint8_t USB_ConfigDescriptor[] = {
_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US); _USB_LANG_ID_(USB_StringLangDescriptor, LANG_US);
// these descriptors are not used in PL2303 emulator! // these descriptors are not used in PL2303 emulator!
_USB_STRING_(USB_StringSerialDescriptor, u"0"); _USB_STRING_(USB_StringSerialDescriptor, u"01");
_USB_STRING_(USB_StringManufacturingDescriptor, u"SAO RAS"); _USB_STRING_(USB_StringManufacturingDescriptor, u"Eddy @ SAO RAS");
_USB_STRING_(USB_StringProdDescriptor, u"HID mouse+keyboard"); _USB_STRING_(USB_StringProdDescriptor, u"USB HID mouse+keyboard");
#ifdef EBUG
uint8_t _2wr = 0;
#define WRITEDUMP(str) do{MSG(str); _2wr = 1;}while(0)
#else
#define WRITEDUMP(str)
#endif
static void wr0(const uint8_t *buf, uint16_t size){ static void wr0(const uint8_t *buf, uint16_t size){
if(setup_packet.wLength < size) size = setup_packet.wLength; if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
if(size < endpoints[0].txbufsz){
EP_WriteIRQ(0, buf, size); EP_WriteIRQ(0, buf, size);
return;
}
while(size){
uint16_t l = size;
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
EP_WriteIRQ(0, buf, l);
buf += l;
size -= l;
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
if(size || needzlp){ // send last data buffer
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
^ USB_EPnR_STAT_TX;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
if((USB->ISTR & USB_ISTR_CTR) == 0){
return;
}
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
}
}
} }
static inline void get_descriptor(){ static inline void get_descriptor(){
switch(setup_packet.wValue){ switch(setup_packet.wValue){
case DEVICE_DESCRIPTOR: case DEVICE_DESCRIPTOR:
WRITEDUMP("DEVICE_DESCRIPTOR");
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor)); wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
break; break;
case CONFIGURATION_DESCRIPTOR: case CONFIGURATION_DESCRIPTOR:
WRITEDUMP("CONFIGURATION_DESCRIPTOR");
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor)); wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
break; break;
case STRING_LANG_DESCRIPTOR: case STRING_LANG_DESCRIPTOR:
WRITEDUMP("STRING_LANG_DESCRIPTOR");
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE); wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
break; break;
case STRING_MAN_DESCRIPTOR: case STRING_MAN_DESCRIPTOR:
WRITEDUMP("STRING_MAN_DESCRIPTOR");
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength); wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
break; break;
case STRING_PROD_DESCRIPTOR: case STRING_PROD_DESCRIPTOR:
WRITEDUMP("STRING_PROD_DESCRIPTOR");
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength); wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
break; break;
case STRING_SN_DESCRIPTOR: case STRING_SN_DESCRIPTOR:
WRITEDUMP("STRING_SN_DESCRIPTOR");
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength); wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
break; break;
case DEVICE_QUALIFIER_DESCRIPTOR: case DEVICE_QUALIFIER_DESCRIPTOR:
WRITEDUMP("DEVICE_QUALIFIER_DESCRIPTOR");
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
break; break;
default: default:
WRITEDUMP("UNK_DES");
break; break;
} }
} }
@ -287,15 +246,12 @@ static inline void std_d2h_req(){
get_descriptor(); get_descriptor();
break; break;
case GET_STATUS: case GET_STATUS:
WRITEDUMP("GET_STATUS");
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
break; break;
case GET_CONFIGURATION: case GET_CONFIGURATION:
WRITEDUMP("GET_CONFIGURATION");
EP_WriteIRQ(0, &configuration, 1); EP_WriteIRQ(0, &configuration, 1);
break; break;
default: default:
WRITEDUMP("80:WR_REQ");
break; break;
} }
} }
@ -303,53 +259,19 @@ static inline void std_d2h_req(){
static inline void std_h2d_req(){ static inline void std_h2d_req(){
switch(setup_packet.bRequest){ switch(setup_packet.bRequest){
case SET_ADDRESS: case SET_ADDRESS:
WRITEDUMP("SET_ADDRESS");
// new address will be assigned later - after acknowlegement or request to host // new address will be assigned later - after acknowlegement or request to host
USB_Dev.USB_Addr = setup_packet.wValue; USB_Dev.USB_Addr = setup_packet.wValue;
break; break;
case SET_CONFIGURATION: case SET_CONFIGURATION:
WRITEDUMP("SET_CONFIGURATION");
// Now device configured // Now device configured
USB_Dev.USB_Status = USB_CONFIGURE_STATE; USB_Dev.USB_Status = USB_STATE_CONFIGURED;
configuration = setup_packet.wValue; configuration = setup_packet.wValue;
break; break;
default: default:
WRITEDUMP("0:WR_REQ");
break; break;
} }
} }
static uint16_t WriteHID_descriptor(uint16_t status){
uint16_t rest = sizeof(HID_ReportDescriptor);
uint8_t *ptr = (uint8_t*)HID_ReportDescriptor;
while(rest){
uint16_t l = rest;
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
EP_WriteIRQ(0, ptr, l);
ptr += l;
rest -= l;
MSG("Sent\n");
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
if(rest || needzlp){ // send last data buffer
status = SET_NAK_RX(status);
status = SET_VALID_TX(status);
status = KEEP_DTOG_TX(status);
status = KEEP_DTOG_RX(status);
status = CLEAR_CTR_RX(status);
status = CLEAR_CTR_TX(status);
USB->ISTR = 0;
USB->EPnR[0] = status;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0);
if((USB->ISTR & USB_ISTR_CTR) == 0){MSG("ERR\n")};
USB->ISTR = 0;
status = USB->EPnR[0];
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
}
}
return status;
}
/* /*
bmRequestType: 76543210 bmRequestType: 76543210
7 direction: 0 - host->device, 1 - device->host 7 direction: 0 - host->device, 1 - device->host
@ -361,117 +283,59 @@ bmRequestType: 76543210
* @param ep - endpoint state * @param ep - endpoint state
* @return data written to EP0R * @return data written to EP0R
*/ */
static uint16_t EP0_Handler(ep_t ep){ static void EP0_Handler(){
uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications
uint8_t reqtype = setup_packet.bmRequestType & 0x7f; uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
if ((ep.rx_flag) && (ep.setup_flag)){ int rxflag = RX_FLAG(epstatus);
if(rxflag && SETUP_FLAG(epstatus)){
switch(reqtype){ switch(reqtype){
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
if(dev2host){ if(dev2host){
std_d2h_req(); std_d2h_req();
}else{ }else{
std_h2d_req(); std_h2d_req();
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
} }
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
case STANDARD_INTERFACE_REQUEST_TYPE: case STANDARD_INTERFACE_REQUEST_TYPE:
if(dev2host && setup_packet.bRequest == GET_DESCRIPTOR){ if(dev2host && setup_packet.bRequest == GET_DESCRIPTOR){
if(setup_packet.wValue == HID_REPORT_DESCRIPTOR){ if(setup_packet.wValue == HID_REPORT_DESCRIPTOR){
WRITEDUMP("HID_REPORT"); wr0(HID_ReportDescriptor, sizeof(HID_ReportDescriptor));
epstatus = WriteHID_descriptor(epstatus);
} }
} }
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
if(setup_packet.bRequest == CLEAR_FEATURE){ if(setup_packet.bRequest == CLEAR_FEATURE){
printu(setup_packet.wValue);
//WRITEDUMP("CLEAR_FEATURE");
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
}else{
WRITEDUMP("02:WR_REQ");
} }
break; break;
case CONTROL_REQUEST_TYPE: case CONTROL_REQUEST_TYPE:
if(setup_packet.bRequest == SET_IDLE_REQUEST){ if(setup_packet.bRequest == SET_IDLE_REQUEST){
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
WRITEDUMP("SET_IDLE_REQUEST");
}else if (setup_packet.bRequest == SET_FEAUTRE){ }else if (setup_packet.bRequest == SET_FEAUTRE){
WRITEDUMP("SET_FEAUTRE");
//set_featuring = 1; //set_featuring = 1;
epstatus = SET_VALID_RX(epstatus);
epstatus = KEEP_STAT_TX(epstatus);
} }
break; break;
default: default:
WRITEDUMP("Bad request");
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} }
}else if (ep.rx_flag || ep.tx_flag){ // got data over EP0 or host acknowlegement || package transmitted }else if(TX_FLAG(epstatus)){
if(ep.rx_flag){
/*if (set_featuring){
set_featuring = 0;
// here we can do something with ep.rx_buf - set_feature
}*/
// Close transaction
#ifdef EBUG
hexdump(ep.rx_buf, ep.rx_cnt);
#endif
}else{ // tx
// now we can change address after enumeration // now we can change address after enumeration
if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
// change state to ADRESSED // change state to ADRESSED
USB_Dev.USB_Status = USB_ADRESSED_STATE; USB_Dev.USB_Status = USB_STATE_ADDRESSED;
} }
} }
// end of transaction epstatus = KEEP_DTOG(USB->EPnR[0]);
epstatus = CLEAR_DTOG_RX(epstatus); if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
epstatus = CLEAR_DTOG_TX(epstatus); else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
epstatus = SET_VALID_RX(epstatus); // keep DTOGs, clear CTR_RX,TX, set RX VALID
epstatus = SET_VALID_TX(epstatus); USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
} }
#ifdef EBUG
if(_2wr){
usart_putchar(' ');
if (ep.rx_flag) usart_putchar('r');
else usart_putchar('t');
printu(setup_packet.wLength);
if(ep.setup_flag) usart_putchar('s');
usart_putchar(' ');
usart_putchar('I');
printu(setup_packet.wIndex);
usart_putchar('V');
printu(setup_packet.wValue);
usart_putchar('R');
printu(setup_packet.bRequest);
usart_putchar('T');
printu(setup_packet.bmRequestType);
usart_putchar(' ');
usart_putchar('0' + ep0dbuflen);
usart_putchar(' ');
hexdump(ep0databuf, ep0dbuflen);
usart_putchar('\n');
_2wr = 0;
}
#endif
return epstatus;
}
#undef WRITEDUMP
static uint16_t lastaddr = USB_EP0_BASEADDR; static uint16_t lastaddr = LASTADDR_DEFAULT;
/** /**
* Endpoint initialisation * Endpoint initialisation
* !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! * !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
@ -482,8 +346,8 @@ static uint16_t lastaddr = USB_EP0_BASEADDR;
* @param uint16_t (*func)(ep_t *ep) - EP handler function * @param uint16_t (*func)(ep_t *ep) - EP handler function
* @return 0 if all OK * @return 0 if all OK
*/ */
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)){ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()){
if(number >= ENDPOINTS_NUM) return 4; // out of configured amount if(number >= STM32ENDPOINTS) return 4; // out of configured amount
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large 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) return 2; // out of btable
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
@ -511,60 +375,48 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t
// standard IRQ handler // standard IRQ handler
void usb_isr(){ void usb_isr(){
// disallow interrupts
USB->CNTR = 0;
if(USB->ISTR & USB_ISTR_RESET){ if(USB->ISTR & USB_ISTR_RESET){
USB->ISTR = 0; usbON = 0;
// Endpoint 0 - CONTROL // Endpoint 0 - CONTROL
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
lastaddr = USB_EP0_BASEADDR; // roll back to beginning of buffer lastaddr = LASTADDR_DEFAULT; // roll back to beginning of buffer
EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler); EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler);
// clear address, leave only enable bit // clear address, leave only enable bit
USB->DADDR = USB_DADDR_EF; USB->DADDR = USB_DADDR_EF;
// state is default - wait for enumeration // state is default - wait for enumeration
USB_Dev.USB_Status = USB_DEFAULT_STATE; USB_Dev.USB_Status = USB_STATE_DEFAULT;
USB->ISTR = 0;
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
} }
if(USB->ISTR & USB_ISTR_CTR){ if(USB->ISTR & USB_ISTR_CTR){
// EP number // EP number
uint8_t n = USB->ISTR & USB_ISTR_EPID; uint8_t n = USB->ISTR & USB_ISTR_EPID;
// copy status register // copy status register
uint16_t epstatus = USB->EPnR[n]; uint16_t epstatus = USB->EPnR[n];
// Calculate flags
endpoints[n].rx_flag = (epstatus & USB_EPnR_CTR_RX) ? 1 : 0;
endpoints[n].setup_flag = (epstatus & USB_EPnR_SETUP) ? 1 : 0;
endpoints[n].tx_flag = (epstatus & USB_EPnR_CTR_TX) ? 1 : 0;
// copy received bytes amount // copy received bytes amount
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
// check direction // check direction
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(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(n == 0){ // control endpoint
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(setup_packet)); EP_Read(0, (uint8_t*)&setup_packet);
ep0dbuflen = 0;
// interrupt handler will be called later // 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;
memcpy(ep0databuf, endpoints[0].rx_buf, ep0dbuflen);
} }
} }
}else{ // IN interrupt - transmit data, only CTR_TX == 1 }else{ // IN interrupt - transmit data, only CTR_TX == 1
// enumeration end could be here (if EP0) // enumeration end could be here (if EP0)
} }
// prepare status field for EP handler if(endpoints[n].func) endpoints[n].func();
endpoints[n].status = epstatus; }
// call EP handler (even if it will change EPnR, it should return new status) if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
epstatus = endpoints[n].func(endpoints[n]); usbON = 0;
// keep DTOG state USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE;
epstatus = KEEP_DTOG_TX(epstatus); USB->ISTR = ~USB_ISTR_SUSP;
epstatus = KEEP_DTOG_RX(epstatus); }
// clear all RX/TX flags if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
epstatus = CLEAR_CTR_RX(epstatus); USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE); // clear suspend flags
epstatus = CLEAR_CTR_TX(epstatus); USB->ISTR = ~USB_ISTR_WKUP;
// refresh EPnR
USB->EPnR[n] = epstatus;
} }
// allow interrupts
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
} }
/** /**
@ -592,13 +444,10 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
* @param size - its size * @param size - its size
*/ */
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
uint16_t status = USB->EPnR[number];
EP_WriteIRQ(number, buf, size); EP_WriteIRQ(number, buf, size);
status = SET_NAK_RX(status); uint16_t status = KEEP_DTOG(USB->EPnR[number]);
status = SET_VALID_TX(status); // keep DTOGs, clear CTR_TX & set TX VALID to start transmission
status = KEEP_DTOG_TX(status); USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
status = KEEP_DTOG_RX(status);
USB->EPnR[number] = status;
} }
/* /*
@ -614,8 +463,3 @@ int EP_Read(uint8_t number, uint8_t *buf){
} }
return n; return n;
} }
// USB status
uint8_t USB_GetState(){
return USB_Dev.USB_Status;
}

View File

@ -29,9 +29,8 @@
#include "usb_defs.h" #include "usb_defs.h"
#define EP0DATABUF_SIZE (64) #define EP0DATABUF_SIZE (64)
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
// Max EP amount (EP0 + other used)
#define ENDPOINTS_NUM 2
// bmRequestType & 0x7f // bmRequestType & 0x7f
#define STANDARD_DEVICE_REQUEST_TYPE 0 #define STANDARD_DEVICE_REQUEST_TYPE 0
#define STANDARD_INTERFACE_REQUEST_TYPE 1 #define STANDARD_INTERFACE_REQUEST_TYPE 1
@ -72,41 +71,29 @@
#define CONTROL_DTR 0x01 #define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02 #define CONTROL_RTS 0x02
// wValue // wValue = DESCR_TYPE<<8 | DESCR_INDEX
#define DEVICE_DESCRIPTOR 0x100 #define DEVICE_DESCRIPTOR 0x0100
#define CONFIGURATION_DESCRIPTOR 0x200 #define CONFIGURATION_DESCRIPTOR 0x0200
#define STRING_LANG_DESCRIPTOR 0x300 #define STRING_LANG_DESCRIPTOR 0x0300
#define STRING_MAN_DESCRIPTOR 0x301 #define STRING_MAN_DESCRIPTOR 0x0301
#define STRING_PROD_DESCRIPTOR 0x302 #define STRING_PROD_DESCRIPTOR 0x0302
#define STRING_SN_DESCRIPTOR 0x303 #define STRING_SN_DESCRIPTOR 0x0303
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 #define DEVICE_QUALIFIER_DESCRIPTOR 0x0600
#define HID_REPORT_DESCRIPTOR 0x2200 #define HID_REPORT_DESCRIPTOR 0x2200
#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
// EPnR bits manipulation // EPnR bits manipulation
#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX)
#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX))
#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX))
#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R
#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX)
#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX))
#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX))
#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX))
#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX))
#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX))
#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX))
#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX))
#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX))
#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX))
#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX))
#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX))
#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX)))
// USB state: uninitialized, addressed, ready for use // USB state: uninitialized, addressed, ready for use, connected
#define USB_DEFAULT_STATE 0 typedef enum{
#define USB_ADRESSED_STATE 1 USB_STATE_DEFAULT,
#define USB_CONFIGURE_STATE 2 USB_STATE_ADDRESSED,
USB_STATE_CONFIGURED
} USB_state;
// EP types // EP types
#define EP_TYPE_BULK 0x00 #define EP_TYPE_BULK 0x00
@ -152,12 +139,8 @@ typedef struct __ep_t{
uint16_t *tx_buf; // transmission buffer address uint16_t *tx_buf; // transmission buffer address
uint16_t txbufsz; // transmission buffer size uint16_t txbufsz; // transmission buffer size
uint8_t *rx_buf; // reception buffer address uint8_t *rx_buf; // reception buffer address
uint16_t (*func)(); // endpoint action function void (*func)(); // endpoint action function
uint16_t status; // status flags
unsigned rx_cnt : 10; // received data counter unsigned rx_cnt : 10; // received data counter
unsigned tx_flag : 1; // transmission flag
unsigned rx_flag : 1; // reception flag
unsigned setup_flag : 1; // this is setup packet (only for EP0)
} ep_t; } ep_t;
// USB status & its address // USB status & its address
@ -166,42 +149,15 @@ typedef struct {
uint16_t USB_Addr; uint16_t USB_Addr;
}usb_dev_t; }usb_dev_t;
typedef struct { extern ep_t endpoints[];
uint32_t dwDTERate; extern usb_dev_t USB_Dev;
uint8_t bCharFormat; extern uint8_t usbON;
#define USB_CDC_1_STOP_BITS 0
#define USB_CDC_1_5_STOP_BITS 1
#define USB_CDC_2_STOP_BITS 2
uint8_t bParityType;
#define USB_CDC_NO_PARITY 0
#define USB_CDC_ODD_PARITY 1
#define USB_CDC_EVEN_PARITY 2
#define USB_CDC_MARK_PARITY 3
#define USB_CDC_SPACE_PARITY 4
uint8_t bDataBits;
} __attribute__ ((packed)) usb_LineCoding;
typedef struct {
uint8_t bmRequestType;
uint8_t bNotificationType;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__ ((packed)) usb_cdc_notification;
//extern ep_t endpoints[];
void USB_Init(); void USB_Init();
uint8_t USB_GetState(); void USB_ResetState();
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)); int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); 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); void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
int EP_Read(uint8_t number, uint8_t *buf); int EP_Read(uint8_t number, uint8_t *buf);
usb_LineCoding getLineCoding();
void WEAK linecoding_handler(usb_LineCoding *lc);
void WEAK clstate_handler(uint16_t val);
void WEAK break_handler();
void WEAK vendor_handler(config_pack_t *packet);
#endif // __USB_LIB_H__ #endif // __USB_LIB_H__

Binary file not shown.

Binary file not shown.

1
F0-nolib/inc/F0 Symbolic link
View File

@ -0,0 +1 @@
/home/eddy/Yandex.Disk/Projects/stm32samples/F0-nolib/inc/Fx

View File

@ -0,0 +1,49 @@
/*
* common_macros.h - common usable things
*
* Copyright 2018 Edward V. Emelianoff <eddy@sao.ru, 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#pragma once
#ifndef __COMMON_MACROS_H__
#define __COMMON_MACROS_H__
#include <stdint.h>
#ifndef TRUE_INLINE
#define TRUE_INLINE __attribute__((always_inline)) static inline
#endif
#ifndef NULL
#define NULL (0)
#endif
// some good things from CMSIS
#define nop() __NOP()
#define pin_toggle(gpioport, gpios) do{ \
register uint32_t __port = gpioport->ODR; \
gpioport->BSRR = ((__port & gpios) << 16) | (~__port & gpios);}while(0)
#define pin_set(gpioport, gpios) do{gpioport->BSRR = gpios;}while(0)
#define pin_clear(gpioport, gpios) do{gpioport->BSRR = ((gpios) << 16);}while(0)
#define pin_read(gpioport, gpios) (gpioport->IDR & (gpios) ? 1 : 0)
#define pin_write(gpioport, gpios) do{gpioport->ODR = gpios;}while(0)
#endif // __COMMON_MACROS_H__

View File

@ -21,19 +21,11 @@
#pragma once #pragma once
#ifndef __STM32F0_H__ #ifndef __STM32F0_H__
#define __STM32F0_H__ #define __STM32F0_H__
#include <stdint.h>
#include "vector.h"
#include "stm32f0xx.h" #include "stm32f0xx.h"
#include "common_macros.h"
#ifndef TRUE_INLINE
#define TRUE_INLINE __attribute__((always_inline)) static inline
#endif
#ifndef NULL
#define NULL (0)
#endif
// some good things from CMSIS
#define nop() __NOP()
/************************* RCC *************************/ /************************* RCC *************************/
// reset clocking registers // reset clocking registers
@ -105,33 +97,34 @@ TRUE_INLINE void sysreset(void){
/* Wait till PLL is used as system clock source */ /* Wait till PLL is used as system clock source */
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL){} while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL){}
} }
/* wrong
TRUE_INLINE void StartHSE(){ TRUE_INLINE void StartHSE(){
// disable PLL // disable PLL
RCC->CR &= ~RCC_CR_PLLON; RCC->CR &= ~RCC_CR_PLLON;
RCC->CR |= RCC_CR_HSEON; RCC->CR |= RCC_CR_HSEON;
while ((RCC->CIR & RCC_CIR_HSERDYF) == 0); while ((RCC->CIR & RCC_CIR_HSERDYF) != 0);
RCC->CIR |= RCC_CIR_HSERDYC; // clear rdy flag RCC->CIR |= RCC_CIR_HSERDYC; // clear rdy flag
// PLL configuration = (HSE) * 12 = ~48 MHz /* PLL configuration = (HSE) * 12 = ~48 MHz */
RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL); RCC->CFGR &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL);
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE_PREDIV | RCC_CFGR_PLLMUL12; RCC->CFGR |= RCC_CFGR_PLLSRC_HSE_PREDIV | RCC_CFGR_PLLMUL12;
RCC->CR |= RCC_CR_PLLON; RCC->CR |= RCC_CR_PLLON;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL){} while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL){}
} */ }
#if defined (STM32F042x6) || defined (STM32F072xb) #if defined (STM32F042x6) || defined (STM32F072xb)
TRUE_INLINE void StartHSI48(){ TRUE_INLINE void StartHSI48(){
RCC->APB1ENR |= RCC_APB1ENR_CRSEN | RCC_APB1ENR_USBEN; // enable CRS (hsi48 sync) & USB // disable PLL
RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB RCC->CR &= ~RCC_CR_PLLON;
RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48 RCC->CR2 &= RCC_CR2_HSI48ON; // turn on HSI48
uint32_t tmout = 16000000; while((RCC->CR2 & RCC_CR2_HSI48RDY) == 0);
while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break;} RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL));
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY; // HSI48/2 * 2 = HSI48
CRS->CFGR &= ~CRS_CFGR_SYNCSRC; RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI48_PREDIV | RCC_CFGR_PLLMUL2);
CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source RCC->CR |= RCC_CR_PLLON;
CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim // select HSI48 as system clock source
CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW; RCC->CFGR |= RCC_CFGR_SW_HSI48;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_HSI48){}
} }
#endif #endif
@ -188,14 +181,6 @@ TRUE_INLINE void StartHSI48(){
#define GPIO_MODER_MODER15_O ((uint32_t)0x40000000) #define GPIO_MODER_MODER15_O ((uint32_t)0x40000000)
#define GPIO_MODER_MODER15_AF ((uint32_t)0x80000000) #define GPIO_MODER_MODER15_AF ((uint32_t)0x80000000)
#define pin_toggle(gpioport, gpios) do{ \
register uint32_t __port = gpioport->ODR; \
gpioport->BSRR = ((__port & gpios) << 16) | (~__port & gpios);}while(0)
#define pin_set(gpioport, gpios) do{gpioport->BSRR = gpios;}while(0)
#define pin_clear(gpioport, gpios) do{gpioport->BRR = gpios;}while(0)
#define pin_read(gpioport, gpios) ((gpioport->IDR & gpios) ? 1 : 0)
#define pin_write(gpioport, gpios) do{gpioport->ODR = gpios;}while(0)
/************************* ADC *************************/ /************************* ADC *************************/
/* inner termometer calibration values /* inner termometer calibration values

View File

@ -73,51 +73,6 @@
#error "Define STM32 family, for example -DSTM32F042x6" #error "Define STM32 family, for example -DSTM32F042x6"
#endif #endif
#ifndef WEAK
#define WEAK __attribute__((weak))
#endif
void WEAK reset_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
void WEAK wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK rtc_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_1_isr(void);
void WEAK exti2_3_isr(void);
void WEAK exti4_15_isr(void);
void WEAK tsc_isr(void);
void WEAK dma1_channel1_isr(void);
void WEAK dma1_channel2_3_isr(void);
void WEAK dma1_channel4_5_isr(void);
void WEAK adc_comp_isr(void);
void WEAK tim1_brk_up_trg_com_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK tim14_isr(void);
void WEAK tim15_isr(void);
void WEAK tim16_isr(void);
void WEAK tim17_isr(void);
void WEAK i2c1_isr(void);
void WEAK i2c2_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_4_isr(void);
void WEAK cec_can_isr(void);
void WEAK usb_isr(void);
/** /**
* @brief CMSIS Device version number V2.2.0 * @brief CMSIS Device version number V2.2.0
*/ */

218
F0-nolib/inc/Fx/stm32f1.h Normal file
View File

@ -0,0 +1,218 @@
/*
* stm32f1.h
*
* Copyright 2017 Edward V. Emelianoff <eddy@sao.ru, 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#pragma once
#ifndef __STM32F1_H__
#define __STM32F1_H__
#include "vector.h"
#include "stm32f10x.h"
#include "common_macros.h"
/************************* RCC *************************/
// reset clocking registers
TRUE_INLINE void sysreset(void){
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL
RCC->CFGR &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
#ifdef STM32F10X_CL
/* Reset PLL2ON and PLL3ON bits */
RCC->CR &= (uint32_t)0xEBFFFFFF;
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x00FF0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
/* Reset CFGR2 register */
RCC->CFGR2 = 0x00000000;
#else
/* Disable all interrupts and clear pending bits */
RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE; /* Vector Table Relocation in Internal FLASH. */
#endif
}
TRUE_INLINE void StartHSE()
{
__IO uint32_t StartUpCounter = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
++StartUpCounter;
} while(!(RCC->CR & RCC_CR_HSERDY) && (StartUpCounter < 10000));
if (RCC->CR & RCC_CR_HSERDY) // HSE started
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
#ifdef STM32F10X_CL
/* Configure PLLs ------------------------------------------------------*/
/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
/* Enable PLL2 */
RCC->CR |= RCC_CR_PLL2ON;
/* Wait till PLL2 is ready */
StartUpCounter = 0;
while((RCC->CR & RCC_CR_PLL2RDY) == 0 && ++StartUpCounter < 1000){}
/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |
RCC_CFGR_PLLMULL9);
#else
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL */
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
StartUpCounter = 0;
while((RCC->CR & RCC_CR_PLLRDY) == 0 && ++StartUpCounter < 1000){}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
StartUpCounter = 0;
while(((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) && ++StartUpCounter < 1000){}
}
else // HSE fails to start-up
{
; // add some code here (use HSI)
}
}
/************************* GPIO *************************/
/**
CNF1: 0 - general output or input; 1 - alternate output or pullup/down input
CNF0: 0 - push/pull, analog or pullup/down input
MODE: 00 - input, 01 - 10MHz, 10 - 2MHz, 11 - 50MHz
Pullup/down: ODR = 0 - pulldown, 1 - pullup
GPIO_BSRR and BRR also works
IDR - input, ODR - output (or pullups management),
*/
// MODE:
#define MODE_INPUT 0
#define MODE_NORMAL 1 // 10MHz
#define MODE_SLOW 2 // 2MHz
#define MODE_FAST 3 // 50MHz
// CNF:
#define CNF_ANALOG (0 << 2)
#define CNF_PPOUTPUT (0 << 2)
#define CNF_FLINPUT (1 << 2)
#define CNF_ODOUTPUT (1 << 2)
#define CNF_PUDINPUT (2 << 2)
#define CNF_AFPP (2 << 2)
#define CNF_AFOD (3 << 2)
#define CRL(pin, cnfmode) ((cnfmode) << (pin*4))
#define CRH(pin, cnfmode) ((cnfmode) << ((pin-8)*4))
/************************* ADC *************************/
/* inner termometer calibration values
* Temp = (V25 - Vsense)/Avg_Slope + 25
*/
#define VREFINT_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7BA))
/************************* IWDG *************************/
#define IWDG_REFRESH (uint32_t)(0x0000AAAA)
#define IWDG_WRITE_ACCESS (uint32_t)(0x00005555)
#define IWDG_START (uint32_t)(0x0000CCCC)
#if 0
/************************* ADC *************************/
/* inner termometer calibration values
* Temp = (V30 - Vsense)/Avg_Slope + 30
* Avg_Slope = (V30 - V110) / (110 - 30)
*/
#define TEMP110_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7C2))
#define TEMP30_CAL_ADDR ((uint16_t*) ((uint32_t) 0x1FFFF7B8))
// VDDA_Actual = 3.3V * VREFINT_CAL / average vref value
#define VDD_CALIB ((uint16_t) (330))
#define VDD_APPLI ((uint16_t) (300))
/************************* USART *************************/
#define USART_CR2_ADD_SHIFT 24
// set address/character match value
#define USART_CR2_ADD_VAL(x) ((x) << USART_CR2_ADD_SHIFT)
//#define do{}while(0)
#endif
#endif // __STM32F1_H__

8377
F0-nolib/inc/Fx/stm32f10x.h Normal file

File diff suppressed because it is too large Load Diff

410
F0-nolib/inc/Fx/vector.h Normal file
View File

@ -0,0 +1,410 @@
/*
* vector.h
*
* Copyright 2017 Edward V. Emelianoff <eddy@sao.ru, 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#pragma once
#ifndef VECTOR_H
#define VECTOR_H
#ifndef WEAK
#define WEAK __attribute__((weak))
#endif
void WEAK reset_handler(void);
void WEAK nmi_handler(void);
void WEAK hard_fault_handler(void);
void WEAK sv_call_handler(void);
void WEAK pend_sv_handler(void);
void WEAK sys_tick_handler(void);
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
void WEAK mem_manage_handler(void);
void WEAK bus_fault_handler(void);
void WEAK usage_fault_handler(void);
void WEAK debug_monitor_handler(void);
#endif
#if defined STM32F0
void WEAK wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK rtc_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_1_isr(void);
void WEAK exti2_3_isr(void);
void WEAK exti4_15_isr(void);
void WEAK tsc_isr(void);
void WEAK dma1_channel1_isr(void);
void WEAK dma1_channel2_3_isr(void);
void WEAK dma1_channel4_5_isr(void);
void WEAK adc_comp_isr(void);
void WEAK tim1_brk_up_trg_com_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK tim14_isr(void);
void WEAK tim15_isr(void);
void WEAK tim16_isr(void);
void WEAK tim17_isr(void);
void WEAK i2c1_isr(void);
void WEAK i2c2_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_4_isr(void);
void WEAK cec_can_isr(void);
void WEAK usb_isr(void);
#elif defined STM32F1
void WEAK wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamper_isr(void);
void WEAK rtc_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_channel1_isr(void);
void WEAK dma1_channel2_isr(void);
void WEAK dma1_channel3_isr(void);
void WEAK dma1_channel4_isr(void);
void WEAK dma1_channel5_isr(void);
void WEAK dma1_channel6_isr(void);
void WEAK dma1_channel7_isr(void);
void WEAK adc1_2_isr(void);
void WEAK usb_hp_can_tx_isr(void);
void WEAK usb_lp_can_rx0_isr(void);
void WEAK can_rx1_isr(void);
void WEAK can_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_isr(void);
void WEAK tim1_up_isr(void);
void WEAK tim1_trg_com_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_wakeup_isr(void);
void WEAK tim8_brk_isr(void);
void WEAK tim8_up_isr(void);
void WEAK tim8_trg_com_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK adc3_isr(void);
void WEAK fsmc_isr(void);
void WEAK sdio_isr(void);
void WEAK tim5_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_isr(void);
void WEAK uart5_isr(void);
void WEAK tim6_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_channel1_isr(void);
void WEAK dma2_channel2_isr(void);
void WEAK dma2_channel3_isr(void);
void WEAK dma2_channel4_5_isr(void);
void WEAK dma2_channel5_isr(void);
void WEAK eth_isr(void);
void WEAK eth_wkup_isr(void);
void WEAK can2_tx_isr(void);
void WEAK can2_rx0_isr(void);
void WEAK can2_rx1_isr(void);
void WEAK can2_sce_isr(void);
void WEAK otg_fs_isr(void);
#elif defined STM32F2
void WEAK nvic_wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamp_stamp_isr(void);
void WEAK rtc_wkup_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_stream0_isr(void);
void WEAK dma1_stream1_isr(void);
void WEAK dma1_stream2_isr(void);
void WEAK dma1_stream3_isr(void);
void WEAK dma1_stream4_isr(void);
void WEAK dma1_stream5_isr(void);
void WEAK dma1_stream6_isr(void);
void WEAK adc_isr(void);
void WEAK can1_tx_isr(void);
void WEAK can1_rx0_isr(void);
void WEAK can1_rx1_isr(void);
void WEAK can1_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_tim9_isr(void);
void WEAK tim1_up_tim10_isr(void);
void WEAK tim1_trg_com_tim11_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_fs_wkup_isr(void);
void WEAK tim8_brk_tim12_isr(void);
void WEAK tim8_up_tim13_isr(void);
void WEAK tim8_trg_com_tim14_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK dma1_stream7_isr(void);
void WEAK fsmc_isr(void);
void WEAK sdio_isr(void);
void WEAK tim5_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_isr(void);
void WEAK uart5_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_stream0_isr(void);
void WEAK dma2_stream1_isr(void);
void WEAK dma2_stream2_isr(void);
void WEAK dma2_stream3_isr(void);
void WEAK dma2_stream4_isr(void);
void WEAK eth_isr(void);
void WEAK eth_wkup_isr(void);
void WEAK can2_tx_isr(void);
void WEAK can2_rx0_isr(void);
void WEAK can2_rx1_isr(void);
void WEAK can2_sce_isr(void);
void WEAK otg_fs_isr(void);
void WEAK dma2_stream5_isr(void);
void WEAK dma2_stream6_isr(void);
void WEAK dma2_stream7_isr(void);
void WEAK usart6_isr(void);
void WEAK i2c3_ev_isr(void);
void WEAK i2c3_er_isr(void);
void WEAK otg_hs_ep1_out_isr(void);
void WEAK otg_hs_ep1_in_isr(void);
void WEAK otg_hs_wkup_isr(void);
void WEAK otg_hs_isr(void);
void WEAK dcmi_isr(void);
void WEAK cryp_isr(void);
void WEAK hash_rng_isr(void);
#elif defined STM32F3
void WEAK nvic_wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamp_stamp_isr(void);
void WEAK rtc_wkup_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_tsc_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_channel1_isr(void);
void WEAK dma1_channel2_isr(void);
void WEAK dma1_channel3_isr(void);
void WEAK dma1_channel4_isr(void);
void WEAK dma1_channel5_isr(void);
void WEAK dma1_channel6_isr(void);
void WEAK dma1_channel7_isr(void);
void WEAK adc1_2_isr(void);
void WEAK usb_hp_can1_tx_isr(void);
void WEAK usb_lp_can1_rx0_isr(void);
void WEAK can1_rx1_isr(void);
void WEAK can1_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_tim15_isr(void);
void WEAK tim1_up_tim16_isr(void);
void WEAK tim1_trg_com_tim17_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_exti23_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_exti24_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_exti25_isr(void);
void WEAK usart2_exti26_isr(void);
void WEAK usart3_exti28_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_wkup_a_isr(void);
void WEAK tim8_brk_isr(void);
void WEAK tim8_up_isr(void);
void WEAK tim8_trg_com_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK adc3_isr(void);
void WEAK reserved_1_isr(void);
void WEAK reserved_2_isr(void);
void WEAK reserved_3_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_exti34_isr(void);
void WEAK uart5_exti35_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_channel1_isr(void);
void WEAK dma2_channel2_isr(void);
void WEAK dma2_channel3_isr(void);
void WEAK dma2_channel4_isr(void);
void WEAK dma2_channel5_isr(void);
void WEAK eth_isr(void);
void WEAK reserved_4_isr(void);
void WEAK reserved_5_isr(void);
void WEAK comp123_isr(void);
void WEAK comp456_isr(void);
void WEAK comp7_isr(void);
void WEAK reserved_6_isr(void);
void WEAK reserved_7_isr(void);
void WEAK reserved_8_isr(void);
void WEAK reserved_9_isr(void);
void WEAK reserved_10_isr(void);
void WEAK reserved_11_isr(void);
void WEAK reserved_12_isr(void);
void WEAK usb_hp_isr(void);
void WEAK usb_lp_isr(void);
void WEAK usb_wkup_isr(void);
void WEAK reserved_13_isr(void);
void WEAK reserved_14_isr(void);
void WEAK reserved_15_isr(void);
void WEAK reserved_16_isr(void);
#elif defined STM32F4
void WEAK nvic_wwdg_isr(void);
void WEAK pvd_isr(void);
void WEAK tamp_stamp_isr(void);
void WEAK rtc_wkup_isr(void);
void WEAK flash_isr(void);
void WEAK rcc_isr(void);
void WEAK exti0_isr(void);
void WEAK exti1_isr(void);
void WEAK exti2_isr(void);
void WEAK exti3_isr(void);
void WEAK exti4_isr(void);
void WEAK dma1_stream0_isr(void);
void WEAK dma1_stream1_isr(void);
void WEAK dma1_stream2_isr(void);
void WEAK dma1_stream3_isr(void);
void WEAK dma1_stream4_isr(void);
void WEAK dma1_stream5_isr(void);
void WEAK dma1_stream6_isr(void);
void WEAK adc_isr(void);
void WEAK can1_tx_isr(void);
void WEAK can1_rx0_isr(void);
void WEAK can1_rx1_isr(void);
void WEAK can1_sce_isr(void);
void WEAK exti9_5_isr(void);
void WEAK tim1_brk_tim9_isr(void);
void WEAK tim1_up_tim10_isr(void);
void WEAK tim1_trg_com_tim11_isr(void);
void WEAK tim1_cc_isr(void);
void WEAK tim2_isr(void);
void WEAK tim3_isr(void);
void WEAK tim4_isr(void);
void WEAK i2c1_ev_isr(void);
void WEAK i2c1_er_isr(void);
void WEAK i2c2_ev_isr(void);
void WEAK i2c2_er_isr(void);
void WEAK spi1_isr(void);
void WEAK spi2_isr(void);
void WEAK usart1_isr(void);
void WEAK usart2_isr(void);
void WEAK usart3_isr(void);
void WEAK exti15_10_isr(void);
void WEAK rtc_alarm_isr(void);
void WEAK usb_fs_wkup_isr(void);
void WEAK tim8_brk_tim12_isr(void);
void WEAK tim8_up_tim13_isr(void);
void WEAK tim8_trg_com_tim14_isr(void);
void WEAK tim8_cc_isr(void);
void WEAK dma1_stream7_isr(void);
void WEAK fsmc_isr(void);
void WEAK sdio_isr(void);
void WEAK tim5_isr(void);
void WEAK spi3_isr(void);
void WEAK uart4_isr(void);
void WEAK uart5_isr(void);
void WEAK tim6_dac_isr(void);
void WEAK tim7_isr(void);
void WEAK dma2_stream0_isr(void);
void WEAK dma2_stream1_isr(void);
void WEAK dma2_stream2_isr(void);
void WEAK dma2_stream3_isr(void);
void WEAK dma2_stream4_isr(void);
void WEAK eth_isr(void);
void WEAK eth_wkup_isr(void);
void WEAK can2_tx_isr(void);
void WEAK can2_rx0_isr(void);
void WEAK can2_rx1_isr(void);
void WEAK can2_sce_isr(void);
void WEAK otg_fs_isr(void);
void WEAK dma2_stream5_isr(void);
void WEAK dma2_stream6_isr(void);
void WEAK dma2_stream7_isr(void);
void WEAK usart6_isr(void);
void WEAK i2c3_ev_isr(void);
void WEAK i2c3_er_isr(void);
void WEAK otg_hs_ep1_out_isr(void);
void WEAK otg_hs_ep1_in_isr(void);
void WEAK otg_hs_wkup_isr(void);
void WEAK otg_hs_isr(void);
void WEAK dcmi_isr(void);
void WEAK cryp_isr(void);
void WEAK hash_rng_isr(void);
void WEAK fpu_isr(void);
void WEAK uart7_isr(void);
void WEAK uart8_isr(void);
void WEAK spi4_isr(void);
void WEAK spi5_isr(void);
void WEAK spi6_isr(void);
void WEAK sai1_isr(void);
void WEAK lcd_tft_isr(void);
void WEAK lcd_tft_err_isr(void);
void WEAK dma2d_isr(void);
#else
#error "Not supported platform"
#endif
#endif // VECTOR_H

View File

@ -1,106 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Generic linker script for STM32 targets using libopencm3. */
/* Memory regions must be defined in the ld script which includes this one. */
/* Enforce emmition of the vector table. */
EXTERN (vector_table)
/* Define the entry point of the output file. */
ENTRY(reset_handler)
/* Define sections. */
SECTIONS
{
.text : {
*(.vectors) /* Vector table */
*(.text*) /* Program code */
. = ALIGN(4);
*(.rodata*) /* Read-only data */
. = ALIGN(4);
} >rom
/* C++ Static constructors/destructors, also used for __attribute__
* ((constructor)) and the likes */
.preinit_array : {
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
} >rom
.init_array : {
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
} >rom
.fini_array : {
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
} >rom
/*
* Another section used by C++ stuff, appears when using newlib with
* 64bit (long long) printf support
*/
.ARM.extab : {
*(.ARM.extab*)
} >rom
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >rom
. = ALIGN(4);
_etext = .;
.data : {
_data = .;
*(.data*) /* Read-write initialized data */
. = ALIGN(4);
_edata = .;
} >ram AT >rom
_data_loadaddr = LOADADDR(.data);
.bss : {
*(.bss*) /* Read-write zero initialized data */
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
/*
* The .eh_frame section appears to be used for C++ exception handling.
* You may need to fix this if you're using C++.
*/
/DISCARD/ : { *(.eh_frame) }
. = ALIGN(4);
end = .;
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@ -0,0 +1,93 @@
/*
********************************************************************************
* *
* Copyright (c) 2017 Andrea Loi *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included *
* in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
* *
********************************************************************************
*/
/******************************************************************************/
/* DON'T EDIT THIS FILE UNLESS YOU KNOW WHAT YOU'RE DOING! */
/******************************************************************************/
/* _isrvectors_tend = 0x00000150; - different for different series */
ENTRY(reset_handler)
SECTIONS {
.vector_table 0x08000000 :
{
_sisrvectors = .;
KEEP(*(.vector_table))
/* ASSERT(. == _isrvectors_tend, "The vector table needs to be 84 elements long!"); */
_eisrvectors = .;
} >rom
.text :
{
. = ALIGN(4);
_stext = .;
*(.text*)
*(.rodata*)
. = ALIGN(4);
_etext = .;
} >rom
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >rom
.ARM : {
*(.ARM.exidx*)
} >rom
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data*)
. = ALIGN(4);
_edata = .;
} >ram AT >rom
.myvars :
{
. = ALIGN(1024);
KEEP(*(.myvars))
} > rom
_ldata = LOADADDR(.data);
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >ram
}
PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram));

View File

@ -8,5 +8,5 @@ MEMORY
} }
/* Include the common ld script. */ /* Include the common ld script. */
INCLUDE stm32f0.ld INCLUDE stm32f01234.ld

View File

@ -8,5 +8,5 @@ MEMORY
} }
/* Include the common ld script. */ /* Include the common ld script. */
INCLUDE stm32f0.ld INCLUDE stm32f01234.ld

View File

@ -8,5 +8,5 @@ MEMORY
} }
/* Include the common ld script. */ /* Include the common ld script. */
INCLUDE stm32f0.ld INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 6K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 10K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 384K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 512K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 768K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,31 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 Karl Palsson <karlp@tweak.net.au>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* Linker script for STM32F100x4, 16K flash, 4K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,218 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>,
* Copyright (C) 2012 chrysn <chrysn@fsfe.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stm32f0xx.h"
/* Initialization template for the interrupt vector table. This definition is
* used by the startup code generator (vector.c) to set the initial values for
* the interrupt handling routines to the chip family specific _isr weak
* symbols. */
#define NVIC_WWDG_IRQ 0
#define NVIC_PVD_IRQ 1
#define NVIC_RTC_IRQ 2
#define NVIC_FLASH_IRQ 3
#define NVIC_RCC_IRQ 4
#define NVIC_EXTI0_1_IRQ 5
#define NVIC_EXTI2_3_IRQ 6
#define NVIC_EXTI4_15_IRQ 7
#define NVIC_TSC_IRQ 8
#define NVIC_DMA1_CHANNEL1_IRQ 9
#define NVIC_DMA1_CHANNEL2_3_IRQ 10
#define NVIC_DMA1_CHANNEL4_5_IRQ 11
#define NVIC_ADC_COMP_IRQ 12
#define NVIC_TIM1_BRK_UP_TRG_COM_IRQ 13
#define NVIC_TIM1_CC_IRQ 14
#define NVIC_TIM2_IRQ 15
#define NVIC_TIM3_IRQ 16
#define NVIC_TIM6_DAC_IRQ 17
#define NVIC_TIM7_IRQ 18
#define NVIC_TIM14_IRQ 19
#define NVIC_TIM15_IRQ 20
#define NVIC_TIM16_IRQ 21
#define NVIC_TIM17_IRQ 22
#define NVIC_I2C1_IRQ 23
#define NVIC_I2C2_IRQ 24
#define NVIC_SPI1_IRQ 25
#define NVIC_SPI2_IRQ 26
#define NVIC_USART1_IRQ 27
#define NVIC_USART2_IRQ 28
#define NVIC_USART3_4_IRQ 29
#define NVIC_CEC_CAN_IRQ 30
#define NVIC_USB_IRQ 31
#define NVIC_IRQ_COUNT 32
#define F0_IRQ_HANDLERS \
[NVIC_WWDG_IRQ] = wwdg_isr, \
[NVIC_PVD_IRQ] = pvd_isr, \
[NVIC_RTC_IRQ] = rtc_isr, \
[NVIC_FLASH_IRQ] = flash_isr, \
[NVIC_RCC_IRQ] = rcc_isr, \
[NVIC_EXTI0_1_IRQ] = exti0_1_isr, \
[NVIC_EXTI2_3_IRQ] = exti2_3_isr, \
[NVIC_EXTI4_15_IRQ] = exti4_15_isr, \
[NVIC_TSC_IRQ] = tsc_isr, \
[NVIC_DMA1_CHANNEL1_IRQ] = dma1_channel1_isr, \
[NVIC_DMA1_CHANNEL2_3_IRQ] = dma1_channel2_3_isr, \
[NVIC_DMA1_CHANNEL4_5_IRQ] = dma1_channel4_5_isr, \
[NVIC_ADC_COMP_IRQ] = adc_comp_isr, \
[NVIC_TIM1_BRK_UP_TRG_COM_IRQ] = tim1_brk_up_trg_com_isr, \
[NVIC_TIM1_CC_IRQ] = tim1_cc_isr, \
[NVIC_TIM2_IRQ] = tim2_isr, \
[NVIC_TIM3_IRQ] = tim3_isr, \
[NVIC_TIM6_DAC_IRQ] = tim6_dac_isr, \
[NVIC_TIM7_IRQ] = tim7_isr, \
[NVIC_TIM14_IRQ] = tim14_isr, \
[NVIC_TIM15_IRQ] = tim15_isr, \
[NVIC_TIM16_IRQ] = tim16_isr, \
[NVIC_TIM17_IRQ] = tim17_isr, \
[NVIC_I2C1_IRQ] = i2c1_isr, \
[NVIC_I2C2_IRQ] = i2c2_isr, \
[NVIC_SPI1_IRQ] = spi1_isr, \
[NVIC_SPI2_IRQ] = spi2_isr, \
[NVIC_USART1_IRQ] = usart1_isr, \
[NVIC_USART2_IRQ] = usart2_isr, \
[NVIC_USART3_4_IRQ] = usart3_4_isr, \
[NVIC_CEC_CAN_IRQ] = cec_can_isr, \
[NVIC_USB_IRQ] = usb_isr
typedef void (*vector_table_entry_t)(void);
typedef void (*funcp_t) (void);
typedef struct {
unsigned int *initial_sp_value; /**< Initial stack pointer value. */
vector_table_entry_t reset;
vector_table_entry_t nmi;
vector_table_entry_t hard_fault;
vector_table_entry_t memory_manage_fault; /* not in CM0 */
vector_table_entry_t bus_fault; /* not in CM0 */
vector_table_entry_t usage_fault; /* not in CM0 */
vector_table_entry_t reserved_x001c[4];
vector_table_entry_t sv_call;
vector_table_entry_t debug_monitor; /* not in CM0 */
vector_table_entry_t reserved_x0034;
vector_table_entry_t pend_sv;
vector_table_entry_t systick;
vector_table_entry_t irq[NVIC_IRQ_COUNT];
} vector_table_t;
/* Symbols exported by the linker script(s): */
extern unsigned _data_loadaddr, _data, _edata, _ebss, _stack;
extern funcp_t __preinit_array_start, __preinit_array_end;
extern funcp_t __init_array_start, __init_array_end;
extern funcp_t __fini_array_start, __fini_array_end;
void main(void);
void blocking_handler(void);
void null_handler(void);
__attribute__ ((section(".vectors")))
vector_table_t vector_table = {
.initial_sp_value = &_stack,
.reset = reset_handler,
.nmi = nmi_handler,
.hard_fault = hard_fault_handler,
.sv_call = sv_call_handler,
.pend_sv = pend_sv_handler,
.systick = sys_tick_handler,
.irq = {
F0_IRQ_HANDLERS
}
};
void WEAK __attribute__ ((naked)) reset_handler(void)
{
volatile unsigned *src, *dest;
funcp_t *fp;
for (src = &_data_loadaddr, dest = &_data;
dest < &_edata;
src++, dest++) {
*dest = *src;
}
while (dest < &_ebss) {
*dest++ = 0;
}
/* Constructors. */
for (fp = &__preinit_array_start; fp < &__preinit_array_end; fp++) {
(*fp)();
}
for (fp = &__init_array_start; fp < &__init_array_end; fp++) {
(*fp)();
}
/* Call the application's entry point. */
main();
/* Destructors. */
for (fp = &__fini_array_start; fp < &__fini_array_end; fp++) {
(*fp)();
}
}
void blocking_handler(void)
{
while (1);
}
void null_handler(void)
{
/* Do nothing. */
}
#pragma weak nmi_handler = null_handler
#pragma weak hard_fault_handler = blocking_handler
#pragma weak sv_call_handler = null_handler
#pragma weak pend_sv_handler = null_handler
#pragma weak sys_tick_handler = null_handler
#pragma weak wwdg_isr = blocking_handler
#pragma weak pvd_isr = blocking_handler
#pragma weak rtc_isr = blocking_handler
#pragma weak flash_isr = blocking_handler
#pragma weak rcc_isr = blocking_handler
#pragma weak exti0_1_isr = blocking_handler
#pragma weak exti2_3_isr = blocking_handler
#pragma weak exti4_15_isr = blocking_handler
#pragma weak tsc_isr = blocking_handler
#pragma weak dma1_channel1_isr = blocking_handler
#pragma weak dma1_channel2_3_isr = blocking_handler
#pragma weak dma1_channel4_5_isr = blocking_handler
#pragma weak adc_comp_isr = blocking_handler
#pragma weak tim1_brk_up_trg_com_isr = blocking_handler
#pragma weak tim1_cc_isr = blocking_handler
#pragma weak tim2_isr = blocking_handler
#pragma weak tim3_isr = blocking_handler
#pragma weak tim6_dac_isr = blocking_handler
#pragma weak tim7_isr = blocking_handler
#pragma weak tim14_isr = blocking_handler
#pragma weak tim15_isr = blocking_handler
#pragma weak tim16_isr = blocking_handler
#pragma weak tim17_isr = blocking_handler
#pragma weak i2c1_isr = blocking_handler
#pragma weak i2c2_isr = blocking_handler
#pragma weak spi1_isr = blocking_handler
#pragma weak spi2_isr = blocking_handler
#pragma weak usart1_isr = blocking_handler
#pragma weak usart2_isr = blocking_handler
#pragma weak usart3_4_isr = blocking_handler
#pragma weak cec_can_isr = blocking_handler
#pragma weak usb_isr = blocking_handler

View File

@ -22,7 +22,6 @@
#include "usart.h" #include "usart.h"
#include "usb.h" #include "usb.h"
#include "usb_lib.h" #include "usb_lib.h"
#include <string.h> // memcpy
volatile uint32_t Tms = 0; volatile uint32_t Tms = 0;
@ -53,7 +52,7 @@ void iwdg_setup(){
while(IWDG->SR){if(--tmout == 0) break;} /* (5) */ while(IWDG->SR){if(--tmout == 0) break;} /* (5) */
IWDG->KR = IWDG_REFRESH; /* (6) */ IWDG->KR = IWDG_REFRESH; /* (6) */
} }
/*
static usb_LineCoding new_lc; static usb_LineCoding new_lc;
static uint8_t lcchange = 0; static uint8_t lcchange = 0;
static void show_new_lc(){ static void show_new_lc(){
@ -112,18 +111,75 @@ void clstate_handler(uint16_t val){
if(val & CONTROL_RTS) SEND(" (RTS)"); if(val & CONTROL_RTS) SEND(" (RTS)");
usart_putchar('\n'); usart_putchar('\n');
} }
*/
// usb getline
char *get_USB(){
static char tmpbuf[512], *curptr = tmpbuf;
static int rest = 511;
uint8_t x = USB_receive((uint8_t*)curptr);
curptr[x] = 0;
if(!x) return NULL;
if(curptr[x-1] == '\n'){
#ifdef EBUG
DBG("fullline");
IWDG->KR = IWDG_REFRESH;
SEND(tmpbuf);
transmit_tbuf();
#endif
curptr = tmpbuf;
rest = 511;
return tmpbuf;
}
curptr += x; rest -= x;
if(rest <= 0){ // buffer overflow
curptr = tmpbuf;
rest = 511;
}
return NULL;
}
#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0)
static const char *parse_cmd(const char *buf){
if(buf[1] != '\n') return buf;
switch(*buf){
case 'L':
USND("Very long test string for USB (it's length is more than 64 bytes).\n"
"This is another part of the string! Can you see all of this?\n");
return "OK\n";
break;
case 'R':
USND("Soft reset\n");
NVIC_SystemReset();
break;
case 'S':
USND("Test string for USB\n");
return "OK\n";
break;
case 'W':
USND("Wait for reboot\n");
while(1){nop();};
break;
default: // help
return
"'L' - send long string over USB\n"
"'R' - software reset\n"
"'S' - send short string over USB\n"
"'W' - test watchdog\n"
;
break;
}
return NULL;
}
int main(void){ int main(void){
uint32_t lastT = 0; uint32_t lastT = 0;
int L = 0;
char *txt;
char tmpbuf[129];
sysreset(); sysreset();
SysTick_Config(6000, 1); SysTick_Config(6000, 1);
gpio_setup(); gpio_setup();
usart_setup(); usart_setup();
SEND("Hello!\n"); MSG("Run");
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
SEND("WDGRESET=1\n"); SEND("WDGRESET=1\n");
@ -144,62 +200,24 @@ int main(void){
transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s
} }
usb_proc(); usb_proc();
uint8_t r = 0; char *txt, *ans;
if((r = USB_receive(tmpbuf, 128))){ if(usartrx()){
tmpbuf[r] = 0; usart_getline(&txt);
SEND("Received data over USB:\n"); ans = (char*)parse_cmd(txt);
SEND(tmpbuf); if(ans) usart_send(ans);
newline();
} }
if(usartrx()){ // usart1 received data, store in in buffer if((txt = get_USB())){
L = usart_getline(&txt); IWDG->KR = IWDG_REFRESH;
char _1st = txt[0]; ans = (char*)parse_cmd(txt);
if(L == 2 && txt[1] == '\n'){ if(ans){
L = 0; uint16_t l = 0; char *p = ans;
switch(_1st){ while(*p++) l++;
case 'C': USB_send((uint8_t*)ans, l);
SEND("USB ");
if(!USB_configured()) SEND("dis");
SEND("connected\n");
break;
case 'L':
USB_send("Very long test string for USB (it's length is more than 64 bytes\n"
"This is another part of the string! Can you see all of this?\n");
SEND("Long test sent\n");
break;
case 'R':
SEND("Soft reset\n");
NVIC_SystemReset();
break;
case 'S':
USB_send("Test string for USB\n");
SEND("Short test sent\n");
break;
case 'W':
SEND("Wait for reboot\n");
while(1){nop();};
break;
default: // help
SEND(
"'C' - test if USB is configured\n"
"'L' - send long string over USB\n"
"'R' - software reset\n"
"'S' - send short string over USB\n"
"'W' - test watchdog\n"
);
break;
} }
} }
transmit_tbuf(); /*if(lcchange){
}
if(L){ // echo all other data
txt[L] = 0;
usart_send(txt);
L = 0;
}
if(lcchange){
show_new_lc(); show_new_lc();
} }*/
} }
return 0; return 0;
} }

Binary file not shown.

View File

@ -24,67 +24,32 @@
#include "usb.h" #include "usb.h"
#include "usb_lib.h" #include "usb_lib.h"
#include "usart.h" #include "usart.h"
#include <string.h> // memcpy, memmove
// incoming buffer size static volatile uint8_t tx_succesfull = 1;
#define IDATASZ (256) static volatile uint8_t rxNE = 0;
static uint8_t incoming_data[IDATASZ];
static uint8_t ovfl = 0;
static uint16_t idatalen = 0;
static int8_t usbON = 0; // ==1 when USB fully configured
static volatile uint8_t tx_succesfull = 0;
// interrupt IN handler (never used?) // interrupt IN handler (never used?)
static uint16_t EP1_Handler(ep_t ep){ static void EP1_Handler(){
uint8_t ep0buf[11]; uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]);
if (ep.rx_flag){ if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX
EP_Read(1, ep0buf); else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX);
ep.status = SET_VALID_TX(ep.status); // clear CTR
ep.status = KEEP_STAT_RX(ep.status); epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX));
}else if (ep.tx_flag){ USB->EPnR[1] = epstatus;
ep.status = SET_VALID_RX(ep.status);
ep.status = SET_STALL_TX(ep.status);
}
return ep.status;
} }
// data IN/OUT handler // data IN/OUT handlers
static uint16_t EP23_Handler(ep_t ep){ static void transmit_Handler(){ // EP3IN
MSG("EP2\n");
if(ep.rx_flag){
int rd = ep.rx_cnt, rest = IDATASZ - idatalen;
if(rd){
if(rd <= rest){
idatalen += EP_Read(2, &incoming_data[idatalen]);
ovfl = 0;
}else{
ep.status = SET_NAK_RX(ep.status);
ovfl = 1;
return ep.status;
}
}
#ifdef EBUG
SEND("receive ");
printu(ep.rx_cnt);
SEND(" bytes, idatalen=");
printu(idatalen);
SEND(" , rest=");
printu(rest);
incoming_data[idatalen] = 0;
SEND(" , the buffer now:\n");
SEND((char*)incoming_data);
usart_putchar('\n');
#endif
// end of transaction: clear DTOGs
ep.status = CLEAR_DTOG_RX(ep.status);
ep.status = CLEAR_DTOG_TX(ep.status);
ep.status = SET_STALL_TX(ep.status);
}else if (ep.tx_flag){
ep.status = KEEP_STAT_TX(ep.status);
tx_succesfull = 1; tx_succesfull = 1;
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
} }
ep.status = SET_VALID_RX(ep.status);
return ep.status; static void receive_Handler(){ // EP2OUT
rxNE = 1;
uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[2]);
USB->EPnR[2] = (epstatus & ~(USB_EPnR_CTR_RX)); // clear RX ctr
} }
void USB_setup(){ void USB_setup(){
@ -100,7 +65,7 @@ void USB_setup(){
CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only
RCC->CFGR |= RCC_CFGR_SW; RCC->CFGR |= RCC_CFGR_SW;
// allow RESET and CTRM interrupts // allow RESET and CTRM interrupts
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM;
// clear flags // clear flags
USB->ISTR = 0; USB->ISTR = 0;
// and activate pullup // and activate pullup
@ -108,97 +73,102 @@ void USB_setup(){
NVIC_EnableIRQ(USB_IRQn); NVIC_EnableIRQ(USB_IRQn);
} }
void usb_proc(){
if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints static int usbwr(const uint8_t *buf, uint16_t l){
if(!usbON){ // endpoints not activated uint32_t ctra = 1000000;
SEND("Configure endpoints\n"); while(--ctra && tx_succesfull == 0){
// make new BULK endpoint IWDG->KR = IWDG_REFRESH;
// 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, 10, 0, EP1_Handler); // IN1 - transmit
EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, EP23_Handler); // OUT2 - receive data
EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, EP23_Handler); // IN3 - transmit data
usbON = 1;
} }
}else{ tx_succesfull = 0;
usbON = 0; EP_Write(3, buf, l);
ctra = 1000000;
while(--ctra && tx_succesfull == 0){
IWDG->KR = IWDG_REFRESH;
}
if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF?
return 0;
}
static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP)
static uint8_t buflen = 0; // amount of symbols in usbbuff
// send next up to 63 bytes of data in usbbuff
static void send_next(){
if(!buflen || !tx_succesfull) return;
tx_succesfull = 0;
EP_Write(3, usbbuff, buflen);
buflen = 0;
}
// unblocking sending - just fill a buffer
void USB_send(const uint8_t *buf, uint16_t len){
if(!usbON || !len) return;
if(len > USB_TXBUFSZ-1 - buflen){
usbwr(usbbuff, buflen);
buflen = 0;
}
if(len > USB_TXBUFSZ-1){
USB_send_blk(buf, len);
return;
}
while(len--) usbbuff[buflen++] = *buf++;
}
// blocking sending
void USB_send_blk(const uint8_t *buf, uint16_t len){
if(!usbON || !len) return; // USB disconnected
if(buflen){
usbwr(usbbuff, buflen);
buflen = 0;
}
int needzlp = 0;
while(len){
if(len == USB_TXBUFSZ) needzlp = 1;
uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len;
if(usbwr(buf, s)) return;
len -= s;
buf += s;
}
if(needzlp){
usbwr(NULL, 0);
} }
} }
void USB_send(char *buf){ void usb_proc(){
uint16_t l = 0, ctr = 0; switch(USB_Dev.USB_Status){
char *p = buf; case USB_STATE_CONFIGURED:
while(*p++) ++l; // make new BULK endpoint
while(l){ // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features)
uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l; EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit
tx_succesfull = 0; EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data
EP_Write(3, (uint8_t*)&buf[ctr], s); EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data
uint32_t ctra = 1000000; USB_Dev.USB_Status = USB_STATE_CONNECTED;
while(--ctra && tx_succesfull == 0); break;
l -= s; case USB_STATE_DEFAULT:
ctr += s; case USB_STATE_ADDRESSED:
if(usbON){
usbON = 0;
}
break;
default: // USB_STATE_CONNECTED - send next data portion
if(!usbON) return;
send_next();
} }
} }
/** /**
* @brief USB_receive * @brief USB_receive
* @param buf (i) - buffer for received data * @param buf (i) - buffer[64] for received data
* @param bufsize - its size
* @return amount of received bytes * @return amount of received bytes
*
int USB_receive(char *buf, int bufsize){
if(!bufsize || !idatalen) return 0;
USB->CNTR = 0;
int sz = (idatalen > bufsize) ? bufsize : idatalen, rest = idatalen - sz;
memcpy(buf, incoming_data, sz);
if(rest > 0){
memmove(incoming_data, &incoming_data[sz], rest);
idatalen = rest;
}else idatalen = 0;
if(ovfl){
EP23_Handler(endpoints[2]);
uint16_t epstatus = USB->EPnR[2];
epstatus = CLEAR_DTOG_RX(epstatus);
epstatus = SET_VALID_RX(epstatus);
USB->EPnR[2] = epstatus;
}
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
return sz;
}*/
int USB_receive(char *buf, int bufsize){
if(bufsize<1 || !idatalen) return 0;
IWDG->KR = IWDG_REFRESH;
int stlen = 0;
for(int i = 0; i < idatalen; ++i){
if(incoming_data[i] == '\n'){
stlen = i+1;
incoming_data[i] = 0;
break;
}
}
if(stlen == 0) return 0;
USB->CNTR = 0;
int sz = (stlen > bufsize) ? bufsize : stlen, rest = idatalen - sz;
memcpy(buf, incoming_data, sz);
if(rest > 0){
memmove(incoming_data, &incoming_data[sz], rest);
idatalen = rest;
}else idatalen = 0;
if(ovfl){
EP23_Handler(endpoints[2]);
uint16_t epstatus = USB->EPnR[2];
epstatus = CLEAR_DTOG_RX(epstatus);
epstatus = SET_VALID_RX(epstatus);
USB->EPnR[2] = epstatus;
}
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
return sz;
}
/**
* @brief USB_configured
* @return 1 if USB is in configured state
*/ */
int USB_configured(){ uint8_t USB_receive(uint8_t *buf){
return usbON; if(!usbON || !rxNE) return 0;
SEND((char*)buf); newline();
uint8_t sz = EP_Read(2, buf);
uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]);
// keep stat_tx & set ACK rx
USB->EPnR[2] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX;
rxNE = 0;
return sz;
} }

View File

@ -30,8 +30,8 @@
void USB_setup(); void USB_setup();
void usb_proc(); void usb_proc();
void USB_send(char *buf); void USB_send(const uint8_t *buf, uint16_t len);
int USB_receive(char *buf, int bufsize); void USB_send_blk(const uint8_t *buf, uint16_t len);
int USB_configured(); uint8_t USB_receive(uint8_t *buf);
#endif // __USB_H__ #endif // __USB_H__

View File

@ -25,24 +25,29 @@
#ifndef __USB_DEFS_H__ #ifndef __USB_DEFS_H__
#define __USB_DEFS_H__ #define __USB_DEFS_H__
#include <stm32f0xx.h> #include <stm32f0.h>
// max endpoints number
#define STM32ENDPOINTS 8
/** /**
* Buffers size definition * Buffers size definition
**/ **/
// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! // !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
#define USB_BTABLE_SIZE 1024 #define USB_BTABLE_SIZE 1024
// 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) // for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303)
#define USB_EP0_BUFSZ 64 #define USB_EP0_BUFSZ 64
// USB transmit buffer size (64 for PL2303) // USB transmit buffer size (64 for PL2303)
#define USB_TXBUFSZ 64 #define USB_TXBUFSZ 64
// USB receive buffer size (64 for PL2303) // USB receive buffer size (64 for PL2303)
#define USB_RXBUFSZ 64 #define USB_RXBUFSZ 64
// EP1 - interrupt - buffer size
#define USB_EP1BUFSZ 8
#define USB_BTABLE_BASE 0x40006000 #define USB_BTABLE_BASE 0x40006000
#ifdef USB_BTABLE
#undef USB_BTABLE #undef USB_BTABLE
#endif
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE)) #define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
#define USB_ISTR_EPID 0x0000000F #define USB_ISTR_EPID 0x0000000F
#define USB_FNR_LSOF_0 0x00000800 #define USB_FNR_LSOF_0 0x00000800
@ -74,15 +79,8 @@
#define USB_TypeDef USB_TypeDef_custom #define USB_TypeDef USB_TypeDef_custom
typedef struct{ typedef struct{
__IO uint32_t EPnR[8]; __IO uint32_t EPnR[STM32ENDPOINTS];
__IO uint32_t RESERVED1; __IO uint32_t RESERVED[STM32ENDPOINTS];
__IO uint32_t RESERVED2;
__IO uint32_t RESERVED3;
__IO uint32_t RESERVED4;
__IO uint32_t RESERVED5;
__IO uint32_t RESERVED6;
__IO uint32_t RESERVED7;
__IO uint32_t RESERVED8;
__IO uint32_t CNTR; __IO uint32_t CNTR;
__IO uint32_t ISTR; __IO uint32_t ISTR;
__IO uint32_t FNR; __IO uint32_t FNR;
@ -100,7 +98,7 @@ typedef struct{
} USB_EPDATA_TypeDef; } USB_EPDATA_TypeDef;
typedef struct{ typedef struct{
__IO USB_EPDATA_TypeDef EP[8]; __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS];
} USB_BtableDef; } USB_BtableDef;
#endif // __USB_DEFS_H__ #endif // __USB_DEFS_H__

View File

@ -23,12 +23,11 @@
#include <stdint.h> #include <stdint.h>
#include "usb_lib.h" #include "usb_lib.h"
#include <string.h> // memcpy
#include "usart.h"
ep_t endpoints[ENDPOINTS_NUM]; ep_t endpoints[STM32ENDPOINTS];
static usb_dev_t USB_Dev; usb_dev_t USB_Dev;
uint8_t usbON = 0;
static usb_LineCoding lineCoding = {115200, 0, 0, 8}; static usb_LineCoding lineCoding = {115200, 0, 0, 8};
static config_pack_t setup_packet; static config_pack_t setup_packet;
static uint8_t ep0databuf[EP0DATABUF_SIZE]; static uint8_t ep0databuf[EP0DATABUF_SIZE];
@ -142,23 +141,19 @@ _USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller");
*/ */
// SET_LINE_CODING // SET_LINE_CODING
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){ void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
MSG("linecoding_handler\n");
} }
// SET_CONTROL_LINE_STATE // SET_CONTROL_LINE_STATE
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){ void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
MSG("clstate_handler\n");
} }
// SEND_BREAK // SEND_BREAK
void WEAK break_handler(){ void WEAK break_handler(){
MSG("break_handler\n");
} }
// handler of vendor requests // handler of vendor requests
void WEAK vendor_handler(config_pack_t *packet){ void WEAK vendor_handler(config_pack_t *packet){
if(packet->bmRequestType & 0x80){ // read if(packet->bmRequestType & 0x80){ // read
//SEND("Read");
uint8_t c; uint8_t c;
switch(packet->wValue){ switch(packet->wValue){
case 0x8484: case 0x8484:
@ -175,26 +170,36 @@ void WEAK vendor_handler(config_pack_t *packet){
} }
EP_WriteIRQ(0, &c, 1); EP_WriteIRQ(0, &c, 1);
}else{ // write ZLP }else{ // write ZLP
//SEND("Write");
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
} }
/*SEND(" vendor, reqt=");
printuhex(packet->bmRequestType);
SEND(", wval=");
printuhex(packet->wValue);
usart_putchar('\n');*/
} }
#ifdef EBUG
uint8_t _2wr = 0;
#define WRITEDUMP(str) do{MSG(str); _2wr = 1;}while(0)
#else
#define WRITEDUMP(str)
#endif
static void wr0(const uint8_t *buf, uint16_t size){ static void wr0(const uint8_t *buf, uint16_t size){
if(setup_packet.wLength < size) size = setup_packet.wLength; if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request
if(size < endpoints[0].txbufsz){
EP_WriteIRQ(0, buf, size); EP_WriteIRQ(0, buf, size);
return;
}
while(size){
uint16_t l = size;
if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz;
EP_WriteIRQ(0, buf, l);
buf += l;
size -= l;
uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0;
if(size || needzlp){ // send last data buffer
uint16_t status = KEEP_DTOG(USB->EPnR[0]);
// keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx
USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX))
^ USB_EPnR_STAT_TX;
uint32_t ctr = 1000000;
while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;};
if((USB->ISTR & USB_ISTR_CTR) == 0){
return;
}
if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0);
}
}
} }
static inline void get_descriptor(){ static inline void get_descriptor(){
@ -221,7 +226,6 @@ static inline void get_descriptor(){
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
break; break;
default: default:
WRITEDUMP("UNK_DES");
break; break;
} }
} }
@ -237,11 +241,9 @@ static inline void std_d2h_req(){
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
break; break;
case GET_CONFIGURATION: case GET_CONFIGURATION:
WRITEDUMP("GET_CONFIGURATION");
EP_WriteIRQ(0, &configuration, 1); EP_WriteIRQ(0, &configuration, 1);
break; break;
default: default:
WRITEDUMP("80:WR_REQ");
break; break;
} }
} }
@ -254,11 +256,10 @@ static inline void std_h2d_req(){
break; break;
case SET_CONFIGURATION: case SET_CONFIGURATION:
// Now device configured // Now device configured
USB_Dev.USB_Status = USB_CONFIGURE_STATE; USB_Dev.USB_Status = USB_STATE_CONFIGURED;
configuration = setup_packet.wValue; configuration = setup_packet.wValue;
break; break;
default: default:
WRITEDUMP("0:WR_REQ");
break; break;
} }
} }
@ -271,40 +272,29 @@ bmRequestType: 76543210
*/ */
/** /**
* Endpoint0 (control) handler * Endpoint0 (control) handler
* @param ep - endpoint state
* @return data written to EP0R
*/ */
static uint16_t EP0_Handler(ep_t ep){ static void EP0_Handler(){
uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications
uint8_t reqtype = setup_packet.bmRequestType & 0x7f; uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
if ((ep.rx_flag) && (ep.setup_flag)){ int rxflag = RX_FLAG(epstatus);
if(rxflag && SETUP_FLAG(epstatus)){
switch(reqtype){ switch(reqtype){
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
if(dev2host){ if(dev2host){
std_d2h_req(); std_d2h_req();
}else{ }else{
std_h2d_req(); std_h2d_req();
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
} }
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request
if(setup_packet.bRequest == CLEAR_FEATURE){ if(setup_packet.bRequest == CLEAR_FEATURE){
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
}else{
WRITEDUMP("02:WR_REQ");
} }
break; break;
case VENDOR_REQUEST_TYPE: case VENDOR_REQUEST_TYPE:
vendor_handler(&setup_packet); vendor_handler(&setup_packet);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
case CONTROL_REQUEST_TYPE: case CONTROL_REQUEST_TYPE:
switch(setup_packet.bRequest){ switch(setup_packet.bRequest){
@ -314,79 +304,43 @@ static uint16_t EP0_Handler(ep_t ep){
case SET_LINE_CODING: // omit this for next stage, when data will come case SET_LINE_CODING: // omit this for next stage, when data will come
break; break;
case SET_CONTROL_LINE_STATE: case SET_CONTROL_LINE_STATE:
usbON = 1;
clstate_handler(setup_packet.wValue); clstate_handler(setup_packet.wValue);
break; break;
case SEND_BREAK: case SEND_BREAK:
usbON = 0;
break_handler(); break_handler();
break; break;
default: default:
WRITEDUMP("undef control req"); break;
} }
if(!dev2host) 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
epstatus = SET_VALID_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
break; break;
default: default:
EP_WriteIRQ(0, (uint8_t *)0, 0); EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} }
}else if (ep.rx_flag){ // got data over EP0 or host acknowlegement }else if(rxflag){ // got data over EP0 or host acknowlegement
if(ep.rx_cnt){ if(endpoints[0].rx_cnt){
// EP_WriteIRQ(0, (uint8_t *)0, 0);
if(setup_packet.bRequest == SET_LINE_CODING){ if(setup_packet.bRequest == SET_LINE_CODING){
//WRITEDUMP("SET_LINE_CODING");
linecoding_handler((usb_LineCoding*)ep0databuf); linecoding_handler((usb_LineCoding*)ep0databuf);
} }
} }
// Close transaction } else if(TX_FLAG(epstatus)){ // package transmitted
epstatus = CLEAR_DTOG_RX(epstatus);
epstatus = CLEAR_DTOG_TX(epstatus);
// wait for new data from host
epstatus = SET_VALID_RX(epstatus);
epstatus = SET_STALL_TX(epstatus);
} else if (ep.tx_flag){ // package transmitted
// now we can change address after enumeration // now we can change address after enumeration
if(USB_Dev.USB_Addr){ if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){
USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr;
// change state to ADRESSED // change state to ADRESSED
USB_Dev.USB_Status = USB_ADRESSED_STATE; USB_Dev.USB_Status = USB_STATE_ADDRESSED;
USB_Dev.USB_Addr = 0; // clear address for re-enumeration
} }
// end of transaction
epstatus = CLEAR_DTOG_RX(epstatus);
epstatus = CLEAR_DTOG_TX(epstatus);
epstatus = SET_VALID_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
} }
#ifdef EBUG epstatus = KEEP_DTOG(USB->EPnR[0]);
if(_2wr){ if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission
usart_putchar(' '); else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged
if (ep.rx_flag) usart_putchar('r'); // keep DTOGs, clear CTR_RX,TX, set RX VALID
else usart_putchar('t'); USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX;
printu(setup_packet.wLength);
if(ep.setup_flag) usart_putchar('s');
usart_putchar(' ');
usart_putchar('I');
printu(setup_packet.wIndex);
usart_putchar('V');
printu(setup_packet.wValue);
usart_putchar('R');
printu(setup_packet.bRequest);
usart_putchar('T');
printu(setup_packet.bmRequestType);
usart_putchar(' ');
usart_putchar('0' + ep0dbuflen);
usart_putchar(' ');
hexdump(ep0databuf, ep0dbuflen);
usart_putchar('\n');
} }
#endif
return epstatus;
}
#undef WRITEDUMP
static uint16_t lastaddr = USB_EP0_BASEADDR; static uint16_t lastaddr = LASTADDR_DEFAULT;
/** /**
* Endpoint initialisation * Endpoint initialisation
* !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! * !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
@ -397,8 +351,8 @@ static uint16_t lastaddr = USB_EP0_BASEADDR;
* @param uint16_t (*func)(ep_t *ep) - EP handler function * @param uint16_t (*func)(ep_t *ep) - EP handler function
* @return 0 if all OK * @return 0 if all OK
*/ */
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)){ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()){
if(number >= ENDPOINTS_NUM) return 4; // out of configured amount if(number >= STM32ENDPOINTS) return 4; // out of configured amount
if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large 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) return 2; // out of btable
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
@ -412,6 +366,7 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t
} }
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr); endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr);
endpoints[number].txbufsz = txsz;
lastaddr += txsz; lastaddr += txsz;
USB_BTABLE->EP[number].USB_COUNT_TX = 0; USB_BTABLE->EP[number].USB_COUNT_TX = 0;
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
@ -427,55 +382,48 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t
void usb_isr(){ void usb_isr(){
if (USB->ISTR & USB_ISTR_RESET){ if (USB->ISTR & USB_ISTR_RESET){
// Reinit registers // Reinit registers
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;
USB->ISTR = 0; USB->ISTR = 0;
// Endpoint 0 - CONTROL // Endpoint 0 - CONTROL
// ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes!
lastaddr = USB_EP0_BASEADDR; // roll back to beginning of buffer lastaddr = LASTADDR_DEFAULT; // roll back to beginning of buffer
EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler); EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler);
// clear address, leave only enable bit // clear address, leave only enable bit
USB->DADDR = USB_DADDR_EF; USB->DADDR = USB_DADDR_EF;
// state is default - wait for enumeration // state is default - wait for enumeration
USB_Dev.USB_Status = USB_DEFAULT_STATE; USB_Dev.USB_Status = USB_STATE_DEFAULT;
} }
if(USB->ISTR & USB_ISTR_CTR){ if(USB->ISTR & USB_ISTR_CTR){
// EP number // EP number
uint8_t n = USB->ISTR & USB_ISTR_EPID; uint8_t n = USB->ISTR & USB_ISTR_EPID;
// copy status register // copy status register
uint16_t epstatus = USB->EPnR[n]; uint16_t epstatus = USB->EPnR[n];
// Calculate flags
endpoints[n].rx_flag = (epstatus & USB_EPnR_CTR_RX) ? 1 : 0;
endpoints[n].setup_flag = (epstatus & USB_EPnR_SETUP) ? 1 : 0;
endpoints[n].tx_flag = (epstatus & USB_EPnR_CTR_TX) ? 1 : 0;
// copy received bytes amount // copy received bytes amount
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
// check direction // check direction
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(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(n == 0){ // control endpoint
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(setup_packet)); EP_Read(0, (uint8_t*)&setup_packet);
ep0dbuflen = 0; ep0dbuflen = 0;
// interrupt handler will be called later // interrupt handler will be called later
}else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf
ep0dbuflen = endpoints[0].rx_cnt; ep0dbuflen = endpoints[0].rx_cnt;
memcpy(ep0databuf, endpoints[0].rx_buf, ep0dbuflen); EP_Read(0, (uint8_t*)&ep0databuf);
} }
} }
}else{ // IN interrupt - transmit data, only CTR_TX == 1
// enumeration end could be here (if EP0)
} }
// prepare status field for EP handler // call EP handler
endpoints[n].status = epstatus; if(endpoints[n].func) endpoints[n].func(endpoints[n]);
// call EP handler (even if it will change EPnR, it should return new status) }
epstatus = endpoints[n].func(endpoints[n]); if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep
// keep DTOG state usbON = 0;
epstatus = KEEP_DTOG_TX(epstatus); USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE;
epstatus = KEEP_DTOG_RX(epstatus); USB->ISTR = ~USB_ISTR_SUSP;
// clear all RX/TX flags }
epstatus = CLEAR_CTR_RX(epstatus); if(USB->ISTR & USB_ISTR_WKUP){ // wakeup
epstatus = CLEAR_CTR_TX(epstatus); USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE); // clear suspend flags
// refresh EPnR USB->ISTR = ~USB_ISTR_WKUP;
USB->EPnR[n] = epstatus;
} }
} }
@ -504,13 +452,10 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
* @param size - its size * @param size - its size
*/ */
void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){
uint16_t status = USB->EPnR[number];
EP_WriteIRQ(number, buf, size); EP_WriteIRQ(number, buf, size);
status = SET_NAK_RX(status); uint16_t status = KEEP_DTOG(USB->EPnR[number]);
status = SET_VALID_TX(status); // keep DTOGs, clear CTR_TX & set TX VALID to start transmission
status = KEEP_DTOG_TX(status); USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX;
status = KEEP_DTOG_RX(status);
USB->EPnR[number] = status;
} }
/* /*
@ -526,8 +471,3 @@ int EP_Read(uint8_t number, uint8_t *buf){
} }
return n; return n;
} }
// USB status
uint8_t USB_GetState(){
return USB_Dev.USB_Status;
}

View File

@ -29,9 +29,8 @@
#include "usb_defs.h" #include "usb_defs.h"
#define EP0DATABUF_SIZE (64) #define EP0DATABUF_SIZE (64)
#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8)
// Max EP amount (EP0 + other used)
#define ENDPOINTS_NUM 4
// bmRequestType & 0x7f // bmRequestType & 0x7f
#define STANDARD_DEVICE_REQUEST_TYPE 0 #define STANDARD_DEVICE_REQUEST_TYPE 0
#define STANDARD_ENDPOINT_REQUEST_TYPE 2 #define STANDARD_ENDPOINT_REQUEST_TYPE 2
@ -77,31 +76,21 @@
#define STRING_SN_DESCRIPTOR 0x303 #define STRING_SN_DESCRIPTOR 0x303
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600 #define DEVICE_QUALIFIER_DESCRIPTOR 0x600
// EPnR bits manipulation #define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX)
#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) #define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX)
#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R #define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP)
#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX)
#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX))
#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX))
#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R
#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX)
#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX))
#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX))
#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX))
#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX))
#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX))
#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX))
#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX))
#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX))
#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX))
#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX))
#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX))
#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX)))
// USB state: uninitialized, addressed, ready for use // EPnR bits manipulation
#define USB_DEFAULT_STATE 0 #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define USB_ADRESSED_STATE 1 #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX))
#define USB_CONFIGURE_STATE 2
// USB state: uninitialized, addressed, ready for use, client connected
typedef enum{
USB_STATE_DEFAULT,
USB_STATE_ADDRESSED,
USB_STATE_CONFIGURED,
USB_STATE_CONNECTED
} USB_state;
// EP types // EP types
#define EP_TYPE_BULK 0x00 #define EP_TYPE_BULK 0x00
@ -145,13 +134,10 @@ typedef struct {
// endpoints state // endpoints state
typedef struct __ep_t{ typedef struct __ep_t{
uint16_t *tx_buf; // transmission buffer address uint16_t *tx_buf; // transmission buffer address
uint16_t txbufsz; // transmission buffer size
uint8_t *rx_buf; // reception buffer address uint8_t *rx_buf; // reception buffer address
uint16_t (*func)(); // endpoint action function void (*func)(); // endpoint action function
uint16_t status; // status flags uint16_t rx_cnt; // received data counter
unsigned rx_cnt : 10; // received data counter
unsigned tx_flag : 1; // transmission flag
unsigned rx_flag : 1; // reception flag
unsigned setup_flag : 1; // this is setup packet (only for EP0)
} ep_t; } ep_t;
// USB status & its address // USB status & its address
@ -184,19 +170,20 @@ typedef struct {
} __attribute__ ((packed)) usb_cdc_notification; } __attribute__ ((packed)) usb_cdc_notification;
extern ep_t endpoints[]; extern ep_t endpoints[];
extern usb_dev_t USB_Dev;
extern uint8_t usbON;
void USB_Init(); void USB_Init();
uint8_t USB_GetState(); uint8_t USB_GetState();
int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)); int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)());
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); 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); void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size);
int EP_Read(uint8_t number, uint8_t *buf); int EP_Read(uint8_t number, uint8_t *buf);
usb_LineCoding getLineCoding(); usb_LineCoding getLineCoding();
void linecoding_handler(usb_LineCoding *lc);
void WEAK linecoding_handler(usb_LineCoding *lc); void clstate_handler(uint16_t val);
void WEAK clstate_handler(uint16_t val); void break_handler();
void WEAK break_handler(); void vendor_handler(config_pack_t *packet);
void WEAK vendor_handler(config_pack_t *packet);
#endif // __USB_LIB_H__ #endif // __USB_LIB_H__

View File

@ -0,0 +1,12 @@
/* Linker script for STM32F042x6, 32K flash, 6K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 32K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 6K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,12 @@
/* Linker script for STM32F051x8, 64K flash, 8K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 8K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld

View File

@ -0,0 +1,12 @@
/* Linker script for STM32F072x8, 64K flash, 16K RAM. */
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
/* Include the common ld script. */
INCLUDE stm32f01234.ld