From 55fcd51645b1cb728f783aceed6d15cfe5b95fa4 Mon Sep 17 00:00:00 2001 From: eddyem Date: Sun, 5 Apr 2020 16:21:48 +0300 Subject: [PATCH] Fix bugs in PL2303 emulation --- F1-nolib/PL2303/Makefile | 2 +- F1-nolib/PL2303/main.c | 53 +++++--- F1-nolib/PL2303/pl2303.bin | Bin 4388 -> 5672 bytes F1-nolib/PL2303/usart.c | 267 +++++++++++++++++++++++++++++++++++++ F1-nolib/PL2303/usart.h | 67 ++++++++++ F1-nolib/PL2303/usb.c | 216 +++++++++++++++--------------- F1-nolib/PL2303/usb.h | 6 +- F1-nolib/PL2303/usb_defs.h | 14 +- F1-nolib/PL2303/usb_lib.c | 176 ++++++++++-------------- F1-nolib/PL2303/usb_lib.h | 59 ++++---- 10 files changed, 579 insertions(+), 281 deletions(-) create mode 100644 F1-nolib/PL2303/usart.c create mode 100644 F1-nolib/PL2303/usart.h diff --git a/F1-nolib/PL2303/Makefile b/F1-nolib/PL2303/Makefile index ec0a80c..c243bd9 100644 --- a/F1-nolib/PL2303/Makefile +++ b/F1-nolib/PL2303/Makefile @@ -10,7 +10,7 @@ DENSITY ?= MD # change this linking script depending on particular MCU model, LDSCRIPT ?= stm32f103x8.ld # debug -DEFS = -DEBUG +#DEFS = -DEBUG INDEPENDENT_HEADERS= diff --git a/F1-nolib/PL2303/main.c b/F1-nolib/PL2303/main.c index 7f60d9e..396a40e 100644 --- a/F1-nolib/PL2303/main.c +++ b/F1-nolib/PL2303/main.c @@ -20,6 +20,7 @@ */ #include "hardware.h" +#include "usart.h" #include "usb.h" #include "usb_lib.h" @@ -53,31 +54,32 @@ void iwdg_setup(){ IWDG->KR = IWDG_REFRESH; /* (6) */ } -char *parse_cmd(char *buf){ +#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 'p': pin_toggle(USBPU_port, USBPU_pin); - USB_send("USB pullup is "); - if(pin_read(USBPU_port, USBPU_pin)) USB_send("off\n"); - else USB_send("on\n"); + USND("USB pullup is "); + if(pin_read(USBPU_port, USBPU_pin)) USND("off\n"); + else USND("on\n"); return NULL; break; 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"); return "OK\n"; break; case 'R': - USB_send("Soft reset\n"); + USND("Soft reset\n"); NVIC_SystemReset(); break; case 'S': - USB_send("Test string for USB\n"); + USND("Test string for USB\n"); return "OK\n"; break; case 'W': - USB_send("Wait for reboot\n"); + USND("Wait for reboot\n"); while(1){nop();}; break; default: // help @@ -97,10 +99,16 @@ char *parse_cmd(char *buf){ char *get_USB(){ static char tmpbuf[512], *curptr = tmpbuf; static int rest = 511; - int x = USB_receive(curptr, rest); + 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; @@ -119,13 +127,15 @@ int main(void){ StartHSE(); hw_setup(); SysTick_Config(72000); -/* + + usart_setup(); + DBG("Start"); if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured - SEND("WDGRESET=1\n"); + SEND("WDGRESET=1"); newline(); } if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured - SEND("SOFTRESET=1\n"); - }*/ + SEND("SOFTRESET=1"); newline(); + } RCC->CSR |= RCC_CSR_RMVF; // remove reset flags USBPU_OFF(); @@ -138,14 +148,25 @@ int main(void){ if(lastT > Tms || Tms - lastT > 499){ LED_blink(LED0); lastT = Tms; + USND("tick\n"); + transmit_tbuf(); } usb_proc(); char *txt, *ans; if((txt = get_USB())){ - ans = parse_cmd(txt); - if(ans) USB_send(ans); + IWDG->KR = IWDG_REFRESH; +#ifdef EBUG + SEND("Got data: "); + SEND(txt); newline(); + transmit_tbuf(); +#endif + ans = (char*)parse_cmd(txt); + if(ans){ + uint16_t l = 0; char *p = ans; + while(*p++) l++; + USB_send((uint8_t*)ans, l); + } } } return 0; } - diff --git a/F1-nolib/PL2303/pl2303.bin b/F1-nolib/PL2303/pl2303.bin index f593677d61d412203b74f31c539d97c26e591969..6805c73a1e1c3b8553b690a59e915d95b3db2a2f 100755 GIT binary patch literal 5672 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 byrs{dSYsI%kl*s+xFP-{@cw_ literal 4388 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 diff --git a/F1-nolib/PL2303/usart.c b/F1-nolib/PL2303/usart.c new file mode 100644 index 0000000..cc318dc --- /dev/null +++ b/F1-nolib/PL2303/usart.c @@ -0,0 +1,267 @@ +/* + * usart.c + * + * Copyright 2018 Edward V. Emelianoff + * + * 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. + */ +#include "stm32f1.h" +#include "usart.h" +#include "usb.h" + +extern volatile uint32_t Tms; +static volatile int idatalen[2] = {0,0}; // received data line length (including '\n') +static volatile int odatalen[2] = {0,0}; + +static int dlen = 0; // length of data (including '\n') in current buffer + +int linerdy = 0, // received data ready + bufovr = 0, // input buffer overfull + txrdy = 1 // transmission done +; + +static int rbufno = 0, tbufno = 0; // current rbuf/tbuf numbers +static uint8_t rbuf[2][UARTBUFSZI], tbuf[2][UARTBUFSZO]; // receive & transmit buffers +static uint8_t *recvdata = NULL; + +/** + * return length of received data (without trailing zero) + */ +uint16_t usart_get(uint8_t **line){ + if(!line) return 0; + *line = NULL; + if(bufovr){ + bufovr = 0; + linerdy = 0; + return 0; + } + if(!linerdy) return 0; + USART1->CR1 &= ~USART_CR1_RXNEIE; // disallow Rx IRQ + dlen = idatalen[rbufno]; + recvdata = rbuf[rbufno]; + // prepare other buffer + rbufno = !rbufno; + idatalen[rbufno] = 0; + recvdata[dlen] = 0; + *line = recvdata; + linerdy = 0; + USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ + return dlen; +} + +// transmit current tbuf and swap buffers +int transmit_tbuf(){ + uint32_t tmout = 7200; + while(!txrdy){ // wait for previos buffer transmission + IWDG->KR = IWDG_REFRESH; + if(--tmout == 0){ + //DMA1_Channel4->CCR &= ~DMA_CCR_EN; + //txrdy = 1; + return 1; + } + } + int l = odatalen[tbufno]; + if(!l){ + return 0; + } + DMA1_Channel4->CCR &= ~DMA_CCR_EN; + DMA1_Channel4->CMAR = (uint32_t) tbuf[tbufno]; // mem + DMA1_Channel4->CNDTR = l; + tbufno = !tbufno; + odatalen[tbufno] = 0; + txrdy = 0; + DMA1_Channel4->CCR |= DMA_CCR_EN; + return 0; +} + +void usart_putchar(const char ch){ + tbuf[tbufno][odatalen[tbufno]++] = ch; + if(odatalen[tbufno] >= UARTBUFSZO){ + while(transmit_tbuf()) IWDG->KR = IWDG_REFRESH; + } +} + +void usart_send(const char *str){ + if(!str) return; + while(*str){ + tbuf[tbufno][odatalen[tbufno]++] = *str++; + if(odatalen[tbufno] >= UARTBUFSZO){ + while(transmit_tbuf()) IWDG->KR = IWDG_REFRESH; + } + } +} + +/** + * @brief usart_senddata - the same as usart_send, but with given length + */ +void usart_senddata(const uint8_t *str, uint16_t len){ + while(len--){ + tbuf[tbufno][odatalen[tbufno]++] = *str++; + if(odatalen[tbufno] >= UARTBUFSZO){ + while(transmit_tbuf()) IWDG->KR = IWDG_REFRESH; + } + } +} + +void newline(){ + usart_putchar('\n'); +} + +/* + * USART speed: baudrate = Fck/(USARTDIV) + * USARTDIV stored in USART->BRR + * + * for 72MHz USARTDIV=72000/f(kboud); so for 115200 USARTDIV=72000/115.2=625 -> BRR=0x271 + * 9600: BRR = 7500 (0x1D4C) + */ + +void usart_setup(){ + uint32_t tmout = 16000000; + // PA9 - Tx, PA10 - Rx + RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN | RCC_APB2ENR_AFIOEN; + RCC->AHBENR |= RCC_AHBENR_DMA1EN; + GPIOA->CRH = CRH(9, CNF_AFPP|MODE_NORMAL) | CRH(10, CNF_FLINPUT|MODE_INPUT); + + // USART1 Tx DMA - Channel4 (Rx - channel 5) + DMA1_Channel4->CPAR = (uint32_t) &USART1->DR; // periph + DMA1_Channel4->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq + // Tx CNDTR set @ each transmission due to data size + NVIC_SetPriority(DMA1_Channel4_IRQn, 3); + NVIC_EnableIRQ(DMA1_Channel4_IRQn); + NVIC_SetPriority(USART1_IRQn, 0); + // setup usart1 + USART1->BRR = 72000000 / 115200; + //USART1->BRR = 24; // 3000000 + USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART + while(!(USART1->SR & USART_SR_TC)){ // polling idle frame Transmission + IWDG->KR = IWDG_REFRESH; + if(--tmout == 0) break; + } + USART1->SR = 0; // clear flags + USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ + USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx + NVIC_EnableIRQ(USART1_IRQn); +} + + +void usart1_isr(){ + #ifdef CHECK_TMOUT + static uint32_t tmout = 0; + #endif + if(USART1->SR & USART_SR_RXNE){ // RX not emty - receive next char + #ifdef CHECK_TMOUT + if(tmout && Tms >= tmout){ // set overflow flag + bufovr = 1; + idatalen[rbufno] = 0; + } + tmout = Tms + TIMEOUT_MS; + if(!tmout) tmout = 1; // prevent 0 + #endif + uint8_t rb = USART1->DR; + if(idatalen[rbufno] < UARTBUFSZI){ // put next char into buf + rbuf[rbufno][idatalen[rbufno]++] = rb; + linerdy = 1; // ready for reading + #ifdef CHECK_TMOUT + // clear timeout at line end + tmout = 0; + #endif + }else{ // buffer overrun + bufovr = 1; + idatalen[rbufno] = 0; + #ifdef CHECK_TMOUT + tmout = 0; + #endif + } + } +} + + +// print 32bit unsigned int +void printu(uint32_t val){ + char bufa[11], bufb[10]; + int l = 0, bpos = 0; + if(!val){ + bufa[0] = '0'; + l = 1; + }else{ + while(val){ + bufb[l++] = val % 10 + '0'; + val /= 10; + } + int i; + bpos += l; + for(i = 0; i < l; ++i){ + bufa[--bpos] = bufb[i]; + } + } + bufa[l + bpos] = 0; + IWDG->KR = IWDG_REFRESH; + usart_send(bufa); +} + +// print 32bit unsigned int as hex +void printuhex(uint32_t val){ + usart_send("0x"); + uint8_t *ptr = (uint8_t*)&val + 3; + int i, j; + for(i = 0; i < 4; ++i, --ptr){ + for(j = 1; j > -1; --j){ + register uint8_t half = (*ptr >> (4*j)) & 0x0f; + if(half < 10) usart_putchar(half + '0'); + else usart_putchar(half - 10 + 'a'); + } + IWDG->KR = IWDG_REFRESH; + } +} +/* +// dump memory buffer +void hexdump(const uint8_t *arr, uint16_t len){ + for(uint16_t l = 0; l < len; ++l, ++arr){ + for(int16_t j = 1; j > -1; --j){ + register uint8_t half = (*arr >> (4*j)) & 0x0f; + if(half < 10) usart_putchar(half + '0'); + else usart_putchar(half - 10 + 'a'); + } + if(l % 16 == 15) usart_putchar('\n'); + else if(l & 1) usart_putchar(' '); + } +} +*/ +void dma1_channel4_isr(){ + DMA1->IFCR = DMA_IFCR_CTCIF4; // clear TC flag + txrdy = 1; +} + +/* +#if USARTNUM == 2 +void dma1_channel4_5_isr(){ + if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx + DMA1->IFCR |= DMA_IFCR_CTCIF4; // clear TC flag + txrdy = 1; + } +} +// USART1 +#elif USARTNUM == 1 +void dma1_channel2_3_isr(){ + if(DMA1->ISR & DMA_ISR_TCIF2){ // Tx + DMA1->IFCR |= DMA_IFCR_CTCIF2; // clear TC flag + txrdy = 1; + } +} +#else +#error "Not implemented" +#endif +*/ diff --git a/F1-nolib/PL2303/usart.h b/F1-nolib/PL2303/usart.h new file mode 100644 index 0000000..73297b9 --- /dev/null +++ b/F1-nolib/PL2303/usart.h @@ -0,0 +1,67 @@ +/* + * usart.h + * + * Copyright 2018 Edward V. Emelianoff + * + * 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 __USART_H__ +#define __USART_H__ + +#include + +// input and output buffers size +#define UARTBUFSZI (64) +#define UARTBUFSZO (64) +// timeout between data bytes +#ifndef TIMEOUT_MS +#define TIMEOUT_MS (1500) +#endif + +// macro for static strings +#define SEND(str) usart_send(str) +#define _s(s) #s +#define STR(s) _s(s) + +#ifdef EBUG +#define DBG(str) do{SEND(__FILE__ " (L" STR(__LINE__) "): " str); newline();}while(0) +#define HERE() do{SEND(STR(__LINE__)); usart_putchar('\n');}while(0) +#define MSG(str) do{SEND(str); usart_putchar('\n');}while(0) +#else +#define MSG(str) +#define HERE() +#define DBG(str) +#endif + +#define usartrx() (linerdy) +#define usartovr() (bufovr) + +extern int linerdy, bufovr, txrdy; + +int transmit_tbuf(); +void usart_setup(); +uint16_t usart_get(uint8_t **line); +void usart_send(const char *str); +void usart_senddata(const uint8_t *str, uint16_t len); +void newline(); +void usart_putchar(const char ch); +void printu(uint32_t val); +void printuhex(uint32_t val); +void hexdump(const uint8_t *arr, uint16_t len); + +#endif // __USART_H__ diff --git a/F1-nolib/PL2303/usb.c b/F1-nolib/PL2303/usb.c index 32effc2..2a9a7be 100644 --- a/F1-nolib/PL2303/usb.c +++ b/F1-nolib/PL2303/usb.c @@ -20,53 +20,36 @@ * MA 02110-1301, USA. * */ +#include "usart.h" #include "usb.h" #include "usb_lib.h" -// incoming buffer size -#define IDATASZ (256) -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 +static volatile uint8_t tx_succesfull = 1; +static volatile uint8_t rxNE = 0; // interrupt IN handler (never used?) -static uint16_t EP1_Handler(ep_t ep){ - if (ep.rx_flag){ - ep.status = SET_VALID_TX(ep.status); - ep.status = KEEP_STAT_RX(ep.status); - }else if (ep.tx_flag){ - ep.status = SET_VALID_RX(ep.status); - ep.status = SET_STALL_TX(ep.status); - } - return ep.status; +static void EP1_Handler(){ + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX + else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); + // clear CTR + epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); + USB->EPnR[1] = epstatus; } -// data IN/OUT handler -static uint16_t EP23_Handler(ep_t ep){ - if(ep.rx_flag){ - int rd = ep.rx_cnt, rest = IDATASZ - idatalen; - if(rd){ - if(rd <= rest){ - idatalen += EP_Read(2, (uint16_t*)&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; - } - ep.status = SET_VALID_RX(ep.status); - return ep.status; +// data IN/OUT handlers +static void transmit_Handler(){ // EP3IN + 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 +} + +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 + DBG("RXh"); } void USB_setup(){ @@ -82,84 +65,103 @@ void USB_setup(){ USB->ISTR = 0; USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // allow only wakeup & reset interrupts NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); - NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn ); +} + +static int usbwr(const uint8_t *buf, uint16_t l){ + uint32_t ctra = 1000000; + while(--ctra && tx_succesfull == 0){ + IWDG->KR = IWDG_REFRESH; + } + tx_succesfull = 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_proc(){ - if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints - if(!usbON){ // endpoints not activated + switch(USB_Dev.USB_Status){ + case USB_STATE_CONFIGURED: // make new BULK endpoint // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features) - EP_Init(1, EP_TYPE_INTERRUPT, 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{ - usbON = 0; - } -} - -void USB_send(const char *buf){ - if(!USB_configured()){ - return; - } - char tmpbuf[USB_TXBUFSZ]; - uint16_t l = 0, ctr = 0; - const char *p = buf; - while(*p++) ++l; - while(l){ - uint16_t proc = 0, s = (l > USB_TXBUFSZ - 1) ? USB_TXBUFSZ - 1: l; - for(int i = 0; i < s; ++i, ++proc){ - char c = buf[ctr+proc]; - /* - if(c == '\n' && the_conf.defflags & FLAG_STRENDRN){ // add '\r' before '\n' - tmpbuf[i++] = '\r'; - if(i == s) ++s; - }*/ - tmpbuf[i] = c; - } - tx_succesfull = 0; - EP_Write(3, (uint8_t*)tmpbuf, s); - uint32_t ctra = 1000000; - while(--ctra && tx_succesfull == 0); - l -= proc; - ctr += proc; + EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit + EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data + EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data + USB_Dev.USB_Status = USB_STATE_CONNECTED; + break; + case USB_STATE_DEFAULT: + case USB_STATE_ADDRESSED: + if(usbON){ + usbON = 0; + } + break; + default: // USB_STATE_CONNECTED - send next data portion + if(!usbON) return; + send_next(); } } /** * @brief USB_receive - * @param buf (i) - buffer for received data - * @param bufsize - its size + * @param buf (i) - buffer[64] for received data * @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; - for(int i = 0; i < sz; ++i) buf[i] = incoming_data[i]; - if(rest > 0){ - uint8_t *ptr = &incoming_data[sz]; - for(int i = 0; i < rest; ++i) incoming_data[i] = *ptr++; - //memmove(incoming_data, &incoming_data[sz], rest); - hardfault on memcpy&memmove - 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; +uint8_t USB_receive(uint8_t *buf){ + if(!usbON || !rxNE) return 0; + DBG("Get data"); + SEND((char*)buf); newline(); + uint8_t sz = EP_Read(2, (uint16_t*)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; } - -/** - * @brief USB_configured - * @return 1 if USB is in configured state - */ -int USB_configured(){ - return usbON; -} diff --git a/F1-nolib/PL2303/usb.h b/F1-nolib/PL2303/usb.h index 75d22b4..894cec7 100644 --- a/F1-nolib/PL2303/usb.h +++ b/F1-nolib/PL2303/usb.h @@ -30,8 +30,8 @@ void USB_setup(); void usb_proc(); -void USB_send(const char *buf); -int USB_receive(char *buf, int bufsize); -int USB_configured(); +void USB_send(const uint8_t *buf, uint16_t len); +void USB_send_blk(const uint8_t *buf, uint16_t len); +uint8_t USB_receive(uint8_t *buf); #endif // __USB_H__ diff --git a/F1-nolib/PL2303/usb_defs.h b/F1-nolib/PL2303/usb_defs.h index d6bc03f..1ac3dd0 100644 --- a/F1-nolib/PL2303/usb_defs.h +++ b/F1-nolib/PL2303/usb_defs.h @@ -41,6 +41,8 @@ #define USB_TXBUFSZ 64 // USB receive buffer size (64 for PL2303) #define USB_RXBUFSZ 64 +// EP1 - interrupt - buffer size +#define USB_EP1BUFSZ 8 #define USB_BTABLE_BASE 0x40006000 #define USB_BASE ((uint32_t)0x40005C00) @@ -91,18 +93,6 @@ typedef struct { __IO uint32_t BTABLE; } USB_TypeDef; -/* -typedef struct{ - __IO uint16_t USB_ADDR_TX; - __IO uint16_t res1; - __IO uint16_t USB_COUNT_TX; - __IO uint16_t res2; - __IO uint16_t USB_ADDR_RX; - __IO uint16_t res3; - __IO uint16_t USB_COUNT_RX; - __IO uint16_t res4; -} USB_EPDATA_TypeDef;*/ - typedef struct{ __IO uint32_t USB_ADDR_TX; __IO uint32_t USB_COUNT_TX; diff --git a/F1-nolib/PL2303/usb_lib.c b/F1-nolib/PL2303/usb_lib.c index 7c278a5..86436e6 100644 --- a/F1-nolib/PL2303/usb_lib.c +++ b/F1-nolib/PL2303/usb_lib.c @@ -26,14 +26,16 @@ ep_t endpoints[STM32ENDPOINTS]; -static usb_dev_t USB_Dev; +usb_dev_t USB_Dev; static usb_LineCoding lineCoding = {115200, 0, 0, 8}; -config_pack_t setup_packet; +static config_pack_t setup_packet; static uint8_t ep0databuf[EP0DATABUF_SIZE]; static uint8_t ep0dbuflen = 0; usb_LineCoding getLineCoding(){return lineCoding;} +uint8_t usbON = 0; // device disconnected from terminal + // definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor #define bcdUSB_L 0x10 #define bcdUSB_H 0x01 @@ -174,8 +176,31 @@ void WEAK vendor_handler(config_pack_t *packet){ } static void wr0(const uint8_t *buf, uint16_t size){ - if(setup_packet.wLength < size) size = setup_packet.wLength; - EP_WriteIRQ(0, buf, size); + if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request + if(size < endpoints[0].txbufsz){ + 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(){ @@ -232,7 +257,7 @@ static inline void std_h2d_req(){ break; case SET_CONFIGURATION: // Now device configured - USB_Dev.USB_Status = USB_CONFIGURE_STATE; + USB_Dev.USB_Status = USB_STATE_CONFIGURED; configuration = setup_packet.wValue; break; default: @@ -248,14 +273,13 @@ bmRequestType: 76543210 */ /** * Endpoint0 (control) handler - * @param ep - endpoint state - * @return data written to EP0R */ -static uint16_t EP0_Handler(ep_t ep){ - uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications +static void EP0_Handler(){ + uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications uint8_t reqtype = setup_packet.bmRequestType & 0x7f; uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; - if ((ep.rx_flag) && (ep.setup_flag)){ + int rxflag = RX_FLAG(epstatus); + if(rxflag && SETUP_FLAG(epstatus)){ switch(reqtype){ case STANDARD_DEVICE_REQUEST_TYPE: // standard device request if(dev2host){ @@ -264,20 +288,14 @@ static uint16_t EP0_Handler(ep_t ep){ std_h2d_req(); EP_WriteIRQ(0, (uint8_t *)0, 0); } - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); break; case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request if(setup_packet.bRequest == CLEAR_FEATURE){ EP_WriteIRQ(0, (uint8_t *)0, 0); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); } break; case VENDOR_REQUEST_TYPE: vendor_handler(&setup_packet); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); break; case CONTROL_REQUEST_TYPE: switch(setup_packet.bRequest){ @@ -287,50 +305,40 @@ static uint16_t EP0_Handler(ep_t ep){ case SET_LINE_CODING: // omit this for next stage, when data will come break; case SET_CONTROL_LINE_STATE: + usbON = 1; clstate_handler(setup_packet.wValue); break; case SEND_BREAK: + usbON = 0; break_handler(); break; default: break; } - //if(!dev2host) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement <- DO WE NEED THIS? TODO!!! - // OR THIS: ??? 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; default: 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 - if(ep.rx_cnt){ - //EP_WriteIRQ(0, (uint8_t *)0, 0); + }else if(rxflag){ // got data over EP0 or host acknowlegement + if(endpoints[0].rx_cnt){ if(setup_packet.bRequest == SET_LINE_CODING){ linecoding_handler((usb_LineCoding*)ep0databuf); } } - // wait for new data from host - epstatus = SET_VALID_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); - } else if (ep.tx_flag){ // package transmitted + } else if(TX_FLAG(epstatus)){ // package transmitted // now we can change address after enumeration if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; // change state to ADRESSED - USB_Dev.USB_Status = USB_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 = LASTADDR_DEFAULT; @@ -343,7 +351,7 @@ static uint16_t lastaddr = LASTADDR_DEFAULT; * @param uint16_t (*func)(ep_t *ep) - EP handler function * @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)(ep_t ep)){ if(number >= STM32ENDPOINTS) return 4; // out of configured amount if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable @@ -358,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; endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr*2); + endpoints[number].txbufsz = txsz; lastaddr += txsz; USB_BTABLE->EP[number].USB_COUNT_TX = 0; USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; @@ -370,17 +379,19 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t //extern int8_t dump; // standard IRQ handler -void usb_isr(){ - if (USB->ISTR & USB_ISTR_RESET){ +void usb_lp_can_rx0_isr(){ + if(USB->ISTR & USB_ISTR_RESET){ + usbON = 0; // 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; // Endpoint 0 - CONTROL // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! lastaddr = LASTADDR_DEFAULT; // clear address, leave only enable bit USB->DADDR = USB_DADDR_EF; - USB_Dev.USB_Status =USB_DEFAULT_STATE; + USB_Dev.USB_Status = USB_STATE_DEFAULT; + USB->ISTR = ~USB_ISTR_RESET; if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){ return; } @@ -390,11 +401,6 @@ void usb_isr(){ uint8_t n = USB->ISTR & USB_ISTR_EPID; // copy status register uint16_t epstatus = USB->EPnR[n]; - // dump = 1; - // 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 endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter // check direction @@ -409,61 +415,19 @@ void usb_isr(){ EP_Read(0, (uint16_t*)&ep0databuf); } } - }else{ // IN interrupt - transmit data, only CTR_TX == 1 - // enumeration end could be here (if EP0) } - // prepare status field for EP handler - endpoints[n].status = epstatus; - // 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; + // call EP handler + if(endpoints[n].func) endpoints[n].func(endpoints[n]); } -} - -/* - if (USB->ISTR & USB_ISTR_PMAOVR) { - MSG("PMAOVR\n"); - // Handle PMAOVR status + if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep + usbON = 0; + USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE; + USB->ISTR = ~USB_ISTR_SUSP; } - if (USB->ISTR & USB_ISTR_SUSP) { - MSG("SUSP\n"); - if (USB->DADDR & 0x7f) { - USB->DADDR = 0; - USB->CNTR &= ~ 0x800; - } + if(USB->ISTR & USB_ISTR_WKUP){ // wakeup + USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE); // clear suspend flags + USB->ISTR = ~USB_ISTR_WKUP; } - if (USB->ISTR & USB_ISTR_ERR) { - MSG("ERR\n"); - // Handle Error - } - if (USB->ISTR & USB_ISTR_WKUP) { - MSG("WKUP\n"); - // Handle Wakeup - } - if (USB->ISTR & USB_ISTR_SOF) { - MSG("SOF\n"); - // Handle SOF - } - if (USB->ISTR & USB_ISTR_ESOF) { - MSG("ESOF\n"); - // Handle ESOF - } - USB->ISTR = 0; -*/ - -void usb_lp_can_rx0_isr(){ - usb_isr(); -} - -void usb_hp_can_tx_isr(){ - usb_isr(); } /** @@ -492,13 +456,10 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ * @param size - its 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); - status = SET_NAK_RX(status); - status = SET_VALID_TX(status); - status = KEEP_DTOG_TX(status); - status = KEEP_DTOG_RX(status); - USB->EPnR[number] = status; + uint16_t status = KEEP_DTOG(USB->EPnR[number]); + // keep DTOGs, clear CTR_TX & set TX VALID to start transmission + USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX; } /* @@ -507,13 +468,16 @@ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ * @return amount of data read */ int EP_Read(uint8_t number, uint16_t *buf){ - int n = (endpoints[number].rx_cnt + 1) >> 1; + int sz = endpoints[number].rx_cnt; + if(!sz) return 0; + endpoints[number].rx_cnt = 0; + int n = (sz + 1) >> 1; uint32_t *in = (uint32_t *)endpoints[number].rx_buf; if(n){ for(int i = 0; i < n; ++i, ++in) buf[i] = *(uint16_t*)in; } - return endpoints[number].rx_cnt; + return sz; } // USB status diff --git a/F1-nolib/PL2303/usb_lib.h b/F1-nolib/PL2303/usb_lib.h index 25398c5..b10c10f 100644 --- a/F1-nolib/PL2303/usb_lib.h +++ b/F1-nolib/PL2303/usb_lib.h @@ -31,8 +31,6 @@ #define EP0DATABUF_SIZE (64) #define LASTADDR_DEFAULT (STM32ENDPOINTS * 8) -// Max EP amount (EP0 + other used) -//#define ENDPOINTS_NUM 4 // bmRequestType & 0x7f #define STANDARD_DEVICE_REQUEST_TYPE 0 #define STANDARD_ENDPOINT_REQUEST_TYPE 2 @@ -78,31 +76,21 @@ #define STRING_SN_DESCRIPTOR 0x303 #define DEVICE_QUALIFIER_DESCRIPTOR 0x600 +#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 -#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) -#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R -#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))) +#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) +#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) // USB state: uninitialized, addressed, ready for use -#define USB_DEFAULT_STATE 0 -#define USB_ADRESSED_STATE 1 -#define USB_CONFIGURE_STATE 2 +typedef enum{ + USB_STATE_DEFAULT, + USB_STATE_ADDRESSED, + USB_STATE_CONFIGURED, + USB_STATE_CONNECTED +} USB_state; // EP types #define EP_TYPE_BULK 0x00 @@ -144,15 +132,12 @@ typedef struct { } config_pack_t; // endpoints state -typedef struct __ep_t{ +typedef struct{ uint16_t *tx_buf; // transmission buffer address + uint16_t txbufsz; // transmission buffer size uint16_t *rx_buf; // reception buffer address - uint16_t (*func)(); // endpoint action function - uint16_t status; // status flags + void (*func)(); // endpoint action function 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; // USB status & its address @@ -185,18 +170,20 @@ typedef struct { } __attribute__ ((packed)) usb_cdc_notification; extern ep_t endpoints[]; +extern usb_dev_t USB_Dev; +extern uint8_t usbON; void USB_Init(); -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)); +void USB_ResetState(); +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_Write(uint8_t number, const uint8_t *buf, uint16_t size); int EP_Read(uint8_t number, uint16_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); +void linecoding_handler(usb_LineCoding *lc); +void clstate_handler(uint16_t val); +void break_handler(); +void vendor_handler(config_pack_t *packet); #endif // __USB_LIB_H__