Add USB, ADC and change address to 4 bits

This commit is contained in:
eddyem
2019-06-07 18:50:55 +03:00
parent 21e9d90500
commit 5b9eb4d3ba
26 changed files with 1679 additions and 299 deletions

6
.gitignore vendored
View File

@@ -7,3 +7,9 @@
*.pho
*.drl
.dropbox.attr
*.bk
*.config
*.creator
*.creator.user*
*.files
*.includes

View File

@@ -1,3 +0,0 @@
- USB bus: PA11 (DM), PA12 (DP)
- ADC inputs: PA0 (V12/4.93), PA1 (V5/2), PA3 (I12 - 1V/A), PA6 (V3.3/2)

View File

@@ -4,7 +4,8 @@ Make regular scan of 8 sensors' pairs.
USART speed 115200. Code for ../../kicad/stm32
### Serial interface commands (ends with '\n'), small letter for only local processing:
- **1...7** - send message to Nth controller, not broadcast (after number should be CAN command)
- **0...7** send message to Nth controller, not broadcast (after number should be CAN command)
- **a** get raw ADC values
- **B** send dummy CAN messages to broadcast address
- **c** show coefficients for all thermosensors
- **D** send dummy CAN messages to master (0) address
@@ -12,8 +13,12 @@ USART speed 115200. Code for ../../kicad/stm32
- **Ff** turn sensors off
- **g** get last CAN address
- **Hh** switch I2C to high speed (100kHz)
- **i** reinit CAN
- **i** reinit CAN with new address (if changed)
- **Jj** get MCU temperature
- **Kk** get values of U and I
- **Ll** switch I2C to low speed (default, 10kHz)
- **Mm** change master id to 0 (**m**) / broadcast (**M**)
- **Oo** turn onboard diagnostic LEDs **O**n or **o**ff (both commands are local!)
- **P** ping everyone over CAN
- **Rr** reinit I2C
- **Ss** start temperature scan
@@ -22,6 +27,10 @@ USART speed 115200. Code for ../../kicad/stm32
- **Vv** very low speed
- **Z** get sensors state over CAN
The command **M** allows to temporaly change master ID of all
controllers to broadcast ID. So all data they sent will be
accessed @ any controller.
### PINOUT
- I2C: PB6 (SCL) & PB7 (SDA)
- USART1: PA9 (Tx) & PA10 (Rx)
@@ -31,7 +40,7 @@ USART speed 115200. Code for ../../kicad/stm32
- sensors' power: PB3 (in, overcurrent), PA8 (out, enable power)
- signal LEDs: PB10 (LED0), PB11 (LED1)
- ADC inputs: PA0 (V12/4.93), PA1 (V5/2), PA3 (I12 - 1V/A), PA6 (V3.3/2)
- controller CAN address: PA13..PA15 (0..2 bits); 0 - master, other address - slave
- controller CAN address: PA13..PA15 (0..2 bits), PB15 (3rd bit); 0 - master, other address - slave
### LEDS
@@ -40,7 +49,7 @@ USART speed 115200. Code for ../../kicad/stm32
### CAN protocol
Variable data length: from 1 to 7 bytes.
First byte of every sequence is command mark (0xA5) or data mark (0x5A).
First (number zero) byte of every sequence is command mark (0xA5) or data mark (0x5A).
Commands:
- CMD_PING request for PONG cmd
@@ -59,12 +68,27 @@ Dummy commands for test purposes:
- CMD_DUMMY1 = 0xAD
Data format:
- 1 byte - Controller number
- 2 byte - Command received
- 3..7 bytes - data
- byte 1 - Controller number
- byte 2 - Command received
- bytes 3..7 - data
Thermal data format:
- 3 byte - Sensor number (10*N + M, where N is multiplexer number, M - number of sensor in pair, i.e. 0,1,10,11,20,21...70,71)
- 4 byte - thermal data H
- 5 byte - thermal data L
- byte 3 - Sensor number (10*N + M, where N is multiplexer number, M - number of sensor in pair, i.e. 0,1,10,11,20,21...70,71)
- byte 4 - thermal data H
- byte 5 - thermal data L
MCU temperature data format:
- byte 3 - data H
- byte 4 - data L
All temperature is in degrC/100
U and I data format:
- byte 2 - type of data (CMD_GETUIVAL0 - V12 and V5, CMD_GETUIVAL1 - I12 and V3.3)
case CMD_GETUIVAL0:
- bytes 3,4 - V12 H/L
- bytes 5,6 - V5 H/L
case CMD_GETUIVAL1:
- bytes 3,4 - I12 H/L
- bytes 5,6 - V33 H/L
Voltage is in V/100, Current is in mA

167
STM32/TSYS_controller/adc.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* This file is part of the TSYS_controller project.
* Copyright 2019 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "adc.h"
/**
* @brief ADC_array - array for ADC channels with median filtering:
* 0..3 - external channels
* 4 - internal Tsens
* 5 - Vref
*/
#define TSENS_CHAN (NUMBER_OF_ADC_CHANNELS-2)
#define VREF_CHAN (NUMBER_OF_ADC_CHANNELS-1)
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
/*
* ADC channels:
* IN0 - V12
* IN1 - V5
* IN3 - I12
* IN6 - V3.3
* IN16- temperature sensor
* IN17- vref
*/
void adc_setup(){
uint16_t ctr = 0; // 0xfff0 - more than 1.3ms
// Enable clocking
/* (1) Enable the peripheral clock of the ADC */
/* (2) Start HSI14 RC oscillator */
/* (3) Wait HSI14 is ready */
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; /* (1) */
RCC->CR2 |= RCC_CR2_HSI14ON; /* (2) */
while ((RCC->CR2 & RCC_CR2_HSI14RDY) == 0 && ++ctr < 0xfff0){}; /* (3) */
// calibration
/* (1) Ensure that ADEN = 0 */
/* (2) Clear ADEN */
/* (3) Launch the calibration by setting ADCAL */
/* (4) Wait until ADCAL=0 */
if ((ADC1->CR & ADC_CR_ADEN) != 0){ /* (1) */
ADC1->CR &= (uint32_t)(~ADC_CR_ADEN); /* (2) */
}
ADC1->CR |= ADC_CR_ADCAL; /* (3) */
ctr = 0; // ADC calibration time is 5.9us
while ((ADC1->CR & ADC_CR_ADCAL) != 0 && ++ctr < 0xfff0){}; /* (4) */
// enable ADC
ctr = 0;
do{
ADC1->CR |= ADC_CR_ADEN;
}while ((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0);
// configure ADC
/* (1) Select HSI14 by writing 00 in CKMODE (reset value) */
/* (2) Select the continuous mode */
/* (3) Select CHSEL0,1,3,6 - ADC inputs, 16,17 - t. sensor and vref */
/* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */
/* (5) Wake-up the VREFINT and Temperature sensor (only for VBAT, Temp sensor and VRefInt) */
// ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */
ADC1->CFGR1 |= ADC_CFGR1_CONT; /* (2)*/
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL3 |
ADC_CHSELR_CHSEL6 | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; /* (3)*/
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */
ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; /* (5) */
// configure DMA for ADC
// DMA for AIN
/* (1) Enable the peripheral clock on DMA */
/* (2) Enable DMA transfer on ADC and circular mode */
/* (3) Configure the peripheral data register address */
/* (4) Configure the memory address */
/* (5) Configure the number of DMA tranfer to be performs on DMA channel 1 */
/* (6) Configure increment, size, interrupts and circular mode */
/* (7) Enable DMA Channel 1 */
RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */
ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* (2) */
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */
DMA1_Channel1->CMAR = (uint32_t)(ADC_array); /* (4) */
DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9; /* (5) */
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC; /* (6) */
DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */
ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversions */
}
/**
* @brief getADCval - calculate median value for `nch` channel
* @param nch - number of channel
* @return
*/
uint16_t getADCval(int nch){
int i, addr = nch;
register uint16_t temp;
#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
uint16_t p[9];
for(i = 0; i < 9; ++i, addr += NUMBER_OF_ADC_CHANNELS) // first we should prepare array for optmed
p[i] = ADC_array[addr];
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
PIX_SORT(p[0], p[3]) ; PIX_SORT(p[5], p[8]) ; PIX_SORT(p[4], p[7]) ;
PIX_SORT(p[3], p[6]) ; PIX_SORT(p[1], p[4]) ; PIX_SORT(p[2], p[5]) ;
PIX_SORT(p[4], p[7]) ; PIX_SORT(p[4], p[2]) ; PIX_SORT(p[6], p[4]) ;
PIX_SORT(p[4], p[2]) ;
return p[4];
#undef PIX_SORT
#undef PIX_SWAP
}
// return MCU temperature (degrees of celsius * 10)
int32_t getMCUtemp(){
getVdd();
// make correction on Vdd value
// int32_t temperature = (int32_t)ADC_array[4] * VddValue / 330;
int32_t ADval = getADCval(TSENS_CHAN);
int32_t temperature = (int32_t) *TEMP30_CAL_ADDR - ADval;
temperature *= (int32_t)(1100 - 300);
temperature /= (int32_t)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR);
temperature += 300;
return(temperature);
}
// return Vdd * 100 (V)
uint32_t getVdd(){
uint32_t vdd = ((uint32_t) *VREFINT_CAL_ADDR) * (uint32_t)330; // 3.3V
vdd /= getADCval(VREF_CHAN);
return vdd;
}
static inline uint32_t Ufromadu(uint8_t nch, uint32_t vdd){
uint32_t ADU = getADCval(nch);
ADU *= vdd;
ADU >>= 12; // /4096
return ADU;
}
/**
* @brief getUval - calculate U & I
* @return array with members:
* 0 - V12 * 100V (U12 = 12Vin/4.93)
* 1 - V5 * 100V (U5 = 5Vin /2)
* 2 - I12 mA (U = 1V/1A)
* 3 - V3.3* 100V (U3.3= 3.3Vin/2)
*/
uint16_t *getUval(){
static uint16_t Uval[4];
uint32_t vdd = getVdd();
uint32_t val = Ufromadu(0, vdd) * 493;
Uval[0] = (uint16_t)(val / 100);
Uval[1] = (uint16_t)(Ufromadu(1, vdd) << 1);
val = getADCval(2) * vdd * 10;
Uval[2] = (uint16_t)(val >> 12);
Uval[3] = (uint16_t)(Ufromadu(3, vdd) << 1);
return Uval;
}

View File

@@ -0,0 +1,31 @@
/*
* This file is part of the TSYS_controller project.
* Copyright 2019 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADC_H
#define ADC_H
#include "stm32f0.h"
#define NUMBER_OF_ADC_CHANNELS (6)
int32_t getMCUtemp();
uint32_t getVdd();
uint16_t getADCval(int nch);
void adc_setup();
uint16_t *getUval();
#endif // ADC_H

View File

@@ -23,7 +23,7 @@
#include <string.h> // memcpy
#include "can.h"
#include "hardware.h"
#include "usart.h"
#include "proto.h"
// incoming message buffer size
#define CAN_INMESSAGE_SIZE (6)
@@ -56,24 +56,17 @@ static int CAN_messagebuf_push(CAN_message *msg){
memcpy(&messages[first_free_idx++], msg, sizeof(CAN_message));
// need to roll?
if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0;
#ifdef EBUG
MSG("1st free: "); usart_putchar('0' + first_free_idx); newline();
#endif
return 0;
}
// pop message from buffer
CAN_message *CAN_messagebuf_pop(){
if(first_nonfree_idx < 0) return NULL;
#ifdef EBUG
MSG("read from idx "); usart_putchar('0' + first_nonfree_idx); newline();
#endif
CAN_message *msg = &messages[first_nonfree_idx++];
if(first_nonfree_idx == CAN_INMESSAGE_SIZE) first_nonfree_idx = 0;
if(first_nonfree_idx == first_free_idx){ // buffer is empty - refresh it
first_nonfree_idx = -1;
first_free_idx = 0;
MSG("refresh buffer\n");
}
return msg;
}
@@ -81,7 +74,7 @@ CAN_message *CAN_messagebuf_pop(){
// get CAN address data from GPIO pins
void readCANID(){
uint8_t CAN_addr = READ_CAN_INV_ADDR();
Controller_address = ~CAN_addr & 0x7;
Controller_address = ~CAN_addr & 0x0f;
CANID = (CAN_ID_PREFIX & CAN_ID_MASK) | Controller_address;
}
@@ -168,42 +161,14 @@ void can_proc(){
RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST;
can_status = CAN_ERROR;
}
#ifdef EBUG
static uint32_t esr, msr, tsr;
uint32_t msr_now = CAN->MSR & 0xf;
if(esr != CAN->ESR || msr != msr_now || tsr != CAN->TSR){
MSG("Timestamp: ");
printu(Tms);
newline();
}
if((CAN->ESR) != esr){
usart_putchar(((CAN->ESR & CAN_ESR_BOFF) != 0) + '0');
esr = CAN->ESR;
MSG("CAN->ESR: ");
printuhex(esr); newline();
}
if(msr_now != msr){
msr = msr_now;
MSG("CAN->MSR & 0xf: ");
printuhex(msr); newline();
}
if(CAN->TSR != tsr){
tsr = CAN->TSR;
MSG("CAN->TSR: ");
printuhex(tsr); newline();
}
#endif
}
CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){
LED_on(LED1); // turn ON LED1 at first data sent/receive
if(!noLED) LED_on(LED1); // turn ON LED1 at first data sent/receive
uint8_t mailbox = 0;
// check first free mailbox
if(CAN->TSR & (CAN_TSR_TME)){
mailbox = (CAN->TSR & CAN_TSR_CODE) >> 24;
#ifdef EBUG
MSG("select "); usart_putchar('0'+mailbox); SEND(" mailbox\n");
#endif
}else{ // no free mailboxes
return CAN_BUSY;
}
@@ -212,18 +177,25 @@ CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){
switch(len){
case 8:
hb |= (uint32_t)msg[7] << 24;
__attribute__((fallthrough));
case 7:
hb |= (uint32_t)msg[6] << 16;
__attribute__((fallthrough));
case 6:
hb |= (uint32_t)msg[5] << 8;
__attribute__((fallthrough));
case 5:
hb |= (uint32_t)msg[4];
__attribute__((fallthrough));
case 4:
lb |= (uint32_t)msg[3] << 24;
__attribute__((fallthrough));
case 3:
lb |= (uint32_t)msg[2] << 16;
__attribute__((fallthrough));
case 2:
lb |= (uint32_t)msg[1] << 8;
__attribute__((fallthrough));
default:
lb |= (uint32_t)msg[0];
}
@@ -238,12 +210,7 @@ static void can_process_fifo(uint8_t fifo_num){
if(fifo_num > 1) return;
CAN_FIFOMailBox_TypeDef *box = &CAN->sFIFOMailBox[fifo_num];
volatile uint32_t *RFxR = (fifo_num) ? &CAN->RF1R : &CAN->RF0R;
LED_on(LED1); // turn ON LED1 at first data sent/receive
MSG("Receive, RDTR=");
#ifdef EBUG
printuhex(box->RDTR);
newline();
#endif
if(!noLED) LED_on(LED1); // turn ON LED1 at first data sent/receive
// read all
while(*RFxR & CAN_RF0R_FMP0){ // amount of messages pending
// CAN_RDTxR: (16-31) - timestamp, (8-15) - filter match index, (0-3) - data length
@@ -257,18 +224,25 @@ static void can_process_fifo(uint8_t fifo_num){
switch(len){
case 8:
dat[7] = hb>>24;
__attribute__((fallthrough));
case 7:
dat[6] = (hb>>16) & 0xff;
__attribute__((fallthrough));
case 6:
dat[5] = (hb>>8) & 0xff;
__attribute__((fallthrough));
case 5:
dat[4] = hb & 0xff;
__attribute__((fallthrough));
case 4:
dat[3] = lb>>24;
__attribute__((fallthrough));
case 3:
dat[2] = (lb>>16) & 0xff;
__attribute__((fallthrough));
case 2:
dat[1] = (lb>>8) & 0xff;
__attribute__((fallthrough));
case 1:
dat[0] = lb & 0xff;
}
@@ -288,9 +262,6 @@ void cec_can_isr(){
CAN->RF1R &= ~CAN_RF1R_FOVR1;
can_status = CAN_FIFO_OVERRUN;
}
#ifdef EBUG
if(can_status == CAN_FIFO_OVERRUN) MSG("fifo 0 overrun\n");
#endif
if(CAN->MSR & CAN_MSR_ERRI){ // Error
CAN->MSR &= ~CAN_MSR_ERRI;
// request abort for problem mailbox

View File

@@ -26,8 +26,8 @@
#include "hardware.h"
// identifier mask (for ORing with Controller_address
#define CAN_ID_MASK ((uint16_t)0x7F8)
// identifier mask
#define CAN_ID_MASK ((uint16_t)0x7F0)
// prefix of identifiers
#define CAN_ID_PREFIX ((uint16_t)0xAAA)
// this is master - Controller_address==0

View File

@@ -20,36 +20,82 @@
* MA 02110-1301, USA.
*
*/
#include "can_process.h"
#include "sensors_manage.h"
#include "adc.h"
#include "can.h"
#include "usart.h"
#include "can_process.h"
#include "proto.h"
#include "sensors_manage.h"
extern volatile uint32_t Tms; // timestamp data
// id of master - all data will be sent to it
static uint16_t master_id = MASTER_ID;
static inline void sendmcut(uint8_t *data){
uint8_t t[3];
uint16_t T = getMCUtemp();
t[0] = data[1]; // command itself
t[1] = (T >> 8) & 0xff; // H
t[2] = T & 0xff; // L
can_send_data(t,3);
}
static inline void senduival(){
uint8_t buf[5];
uint16_t *vals = getUval();
buf[0] = CMD_GETUIVAL0; // V12 and V5
buf[1] = vals[0] >> 8; // H
buf[2] = vals[0] & 0xff;// L
buf[3] = vals[1] >> 8; // -//-
buf[4] = vals[1] & 0xff;
can_send_data(buf, 5);
buf[0] = CMD_GETUIVAL1; // I12 and V3.3
buf[1] = vals[2] >> 8; // H
buf[2] = vals[2] & 0xff;// L
buf[3] = vals[3] >> 8; // -//-
buf[4] = vals[3] & 0xff;
can_send_data(buf, 5);
}
static inline void showui(char *v1, char *v2, uint8_t *data){
char N = '0' + data[1];
addtobuf(v1);
bufputchar(N);
bufputchar('=');
uint16_t v = data[3]<<8 | data[4];
printu(v);
newline();
addtobuf(v2);
bufputchar(N);
bufputchar('=');
v = data[5]<<8 | data[6];
printu(v);
}
void can_messages_proc(){
CAN_message *can_mesg = CAN_messagebuf_pop();
if(!can_mesg) return; // no data in buffer
uint8_t len = can_mesg->length;
IWDG->KR = IWDG_REFRESH;
#ifdef EBUG
SEND("got message, len: "); usart_putchar('0' + len);
SEND("got message, len: "); bufputchar('0' + len);
SEND(", data: ");
uint8_t ctr;
for(ctr = 0; ctr < len; ++ctr){
printuhex(can_mesg->data[ctr]);
usart_putchar(' ');
bufputchar(' ');
}
newline();
#endif
uint8_t *data = can_mesg->data, b[2];
b[0] = data[1];
int16_t t;
if(data[0] == COMMAND_MARK){ // process commands
if(len < 2) return;
switch(data[1]){
case CMD_DUMMY0:
case CMD_DUMMY1:
SEND("DUMMY");
usart_putchar('0' + (data[1]==CMD_DUMMY0 ? 0 : 1));
bufputchar('0' + (data[1]==CMD_DUMMY0 ? 0 : 1));
newline();
break;
case CMD_PING: // pong
@@ -83,34 +129,62 @@ void can_messages_proc(){
case CMD_REINIT_I2C:
i2c_setup(CURRENT_SPEED);
break;
case CMD_CHANGE_MASTER_B:
master_id = BCAST_ID;
break;
case CMD_CHANGE_MASTER:
master_id = MASTER_ID;
break;
case CMD_GETMCUTEMP:
sendmcut(data);
break;
case CMD_GETUIVAL:
senduival();
break;
}
}else if(data[0] == DATA_MARK){ // process received data
if(len < 3) return;
switch(data[2]){
case CMD_PING:
SEND("PONG");
usart_putchar('0' + data[1]);
bufputchar('0' + data[1]);
break;
case CMD_SENSORS_STATE:
SEND("SSTATE");
usart_putchar('0' + data[1]);
usart_putchar('=');
bufputchar('0' + data[1]);
bufputchar('=');
printu(data[3]);
break;
case CMD_START_MEASUREMENT: // temperature
if(len != 6) return;
usart_putchar('T');
usart_putchar('0' + data[1]);
usart_putchar('_');
bufputchar('T');
bufputchar('0' + data[1]);
bufputchar('_');
printu(data[3]);
usart_putchar('=');
int16_t t = data[4]<<8 | data[5];
bufputchar('=');
t = data[4]<<8 | data[5];
if(t < 0){
t = -t;
usart_putchar('-');
bufputchar('-');
}
printu(t);
#pragma message("TODO: process received T over USB!")
break;
case CMD_GETMCUTEMP:
addtobuf("TMCU");
bufputchar('0' + data[1]);
bufputchar('=');
t = data[3]<<8 | data[4];
if(t < 0){
bufputchar('-');
t = -t;
}
printu(t);
break;
case CMD_GETUIVAL0: // V12 and V5
showui("V12_", "V5_", data);
break;
case CMD_GETUIVAL1: // I12 and V3.3
showui("I12_", "V33_", data);
break;
default:
SEND("UNKNOWN_DATA");
@@ -124,6 +198,7 @@ static CAN_status try2send(uint8_t *buf, uint8_t len, uint16_t id){
uint32_t Tstart = Tms;
while(Tms - Tstart < SEND_TIMEOUT_MS){
if(CAN_OK == can_send(buf, len, id)) return CAN_OK;
IWDG->KR = IWDG_REFRESH;
}
SEND("CAN_BUSY\n");
return CAN_BUSY;
@@ -136,7 +211,7 @@ static CAN_status try2send(uint8_t *buf, uint8_t len, uint16_t id){
* @param cmd - command to send
*/
CAN_status can_send_cmd(uint16_t targetID, uint8_t cmd){
if(Controller_address != 0 && cmd != CMD_DUMMY0 && cmd != CMD_DUMMY1) return CAN_NOTMASTER;
//if(Controller_address != 0 && cmd != CMD_DUMMY0 && cmd != CMD_DUMMY1) return CAN_NOTMASTER;
uint8_t buf[2];
buf[0] = COMMAND_MARK;
buf[1] = cmd;
@@ -151,7 +226,7 @@ CAN_status can_send_data(uint8_t *data, uint8_t len){
buf[1] = Controller_address;
int i;
for(i = 0; i < len; ++i) buf[i+2] = *data++;
return try2send(buf, len+2, MASTER_ID);
return try2send(buf, len+2, master_id);
}
/**

View File

@@ -41,6 +41,12 @@ typedef enum{
CMD_LOW_SPEED, // low I2C speed (10kHz)
CMD_HIGH_SPEED, // high I2C speed (100kHz)
CMD_REINIT_I2C, // reinit I2C with current speed
CMD_CHANGE_MASTER_B, // change master id to broadcast
CMD_CHANGE_MASTER, // change master id to 0
CMD_GETMCUTEMP, // MCU temperature value
CMD_GETUIVAL, // request to get values of V12, V5, I12 and V3.3
CMD_GETUIVAL0, // answer with values of V12 and V5
CMD_GETUIVAL1, // answer with values of I12 and V3.3
// dummy commands for test purposes
CMD_DUMMY0 = 0xDA,
CMD_DUMMY1 = 0xAD

View File

@@ -22,7 +22,6 @@
*/
#include "hardware.h"
#include "usart.h"
I2C_SPEED curI2Cspeed = LOW_SPEED;
@@ -43,12 +42,14 @@ void gpio_setup(void){
// PA8 - power enable
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER8)) |
GPIO_MODER_MODER8_O;
// PA13..15 - CAN address, pullup inputs
// PA13..15 (low bits) + PB15 (high bit) - CAN address, pullup inputs
GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPDR13 | GPIO_PUPDR_PUPDR14 |
GPIO_PUPDR_PUPDR15)
) |
GPIO_PUPDR_PUPDR13_0 | GPIO_PUPDR_PUPDR14_0 |
GPIO_PUPDR_PUPDR15_0;
GPIOB->PUPDR = (GPIOB->PUPDR & ~(GPIO_PUPDR_PUPDR15)) |
GPIO_PUPDR_PUPDR15_0;
pin_set(LED0_port, LED0_pin); // clear LEDs
pin_set(LED1_port, LED1_pin);
}
@@ -59,7 +60,6 @@ void i2c_setup(I2C_SPEED speed){
}else{
curI2Cspeed = speed;
}
MSG("setup I2C\n");
I2C1->CR1 = 0;
#if I2CPINS == 910
/*

View File

@@ -75,7 +75,7 @@
#define SENSORS_OVERCURNT() ((1<<3) != (GPIOB->IDR & (1<<3)))
// CAN address - PA13..PA15
#define READ_CAN_INV_ADDR() ((GPIOA->IDR & (0x7<<13))>>13)
#define READ_CAN_INV_ADDR() (((GPIOA->IDR & (0x7<<13))>>13) | ((GPIOB->IDR & (1<<15)) >> 12))
extern uint8_t Controller_address;
typedef enum{

View File

@@ -20,10 +20,8 @@
* MA 02110-1301, USA.
*
*/
#include "stm32f0.h"
#include "hardware.h"
#include "i2c.h"
#include "usart.h"
/**
* I2C for TSYS01
@@ -53,36 +51,38 @@ static uint32_t cntr;
uint8_t write_i2c(uint8_t addr, uint8_t data){
cntr = Tms;
I2C1->ICR = 0x3f38; // clear all errors
while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > I2C_TIMEOUT){
//MSG("always busy\n");
while(I2C1->ISR & I2C_ISR_BUSY){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
return 0; // check busy
}
}}
cntr = Tms;
while(I2C1->CR2 & I2C_CR2_START) if(Tms - cntr > I2C_TIMEOUT){
//MSG("always start\n");
while(I2C1->CR2 & I2C_CR2_START){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
return 0; // check start
}
}}
//I2C1->ICR = 0x3f38; // clear all errors
I2C1->CR2 = 1<<16 | addr | I2C_CR2_AUTOEND; // 1 byte, autoend
// now start transfer
I2C1->CR2 |= I2C_CR2_START;
cntr = Tms;
while(!(I2C1->ISR & I2C_ISR_TXIS)){ // ready to transmit
IWDG->KR = IWDG_REFRESH;
if(I2C1->ISR & I2C_ISR_NACKF){
I2C1->ICR |= I2C_ICR_NACKCF;
//I2C1->ICR = 0x3f38;
//MSG("NACK\n");
return 0;
}
if(Tms - cntr > I2C_TIMEOUT){
//I2C1->ICR = 0x3f38;
//MSG("Timeout\n");
return 0;
}
}
I2C1->TXDR = data; // send data
// wait for data gone
while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > I2C_TIMEOUT){break;}
while(I2C1->ISR & I2C_ISR_BUSY){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){break;}
}
return 1;
}
@@ -94,15 +94,17 @@ uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes){
uint32_t result = 0;
cntr = Tms;
//MSG("read_i2c\n");
while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > I2C_TIMEOUT){
//MSG("always busy\n");
while(I2C1->ISR & I2C_ISR_BUSY){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
return 0; // check busy
}
}}
cntr = Tms;
while(I2C1->CR2 & I2C_CR2_START) if(Tms - cntr > I2C_TIMEOUT){
//MSG("always start\n");
while(I2C1->CR2 & I2C_CR2_START){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
return 0; // check start
}
}}
// I2C1->ICR = 0x3f38; // clear all errors
// read N bytes
I2C1->CR2 = (nbytes<<16) | addr | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN;
@@ -111,15 +113,12 @@ uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes){
cntr = Tms;
for(i = 0; i < nbytes; ++i){
while(!(I2C1->ISR & I2C_ISR_RXNE)){ // wait for data
IWDG->KR = IWDG_REFRESH;
if(I2C1->ISR & I2C_ISR_NACKF){
I2C1->ICR |= I2C_ICR_NACKCF;
//I2C1->ICR = 0x3f38;
//MSG("NACK\n");
return 0;
}
if(Tms - cntr > I2C_TIMEOUT){
//I2C1->ICR = 0x3f38;
//MSG("Timeout\n");
return 0;
}
}

View File

@@ -21,6 +21,8 @@
*
*/
#include "stm32f0.h"
// timeout of I2C bus in ms
#define I2C_TIMEOUT (100)
// CSB=1, address 1110110

View File

@@ -18,14 +18,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#include "hardware.h"
#include "usart.h"
#include "i2c.h"
#include "sensors_manage.h"
#include "adc.h"
#include "can.h"
#include "can_process.h"
#include "hardware.h"
#include "i2c.h"
#include "proto.h"
#include "sensors_manage.h"
#include "usart.h"
#include "usb.h"
#pragma message("USARTNUM=" STR(USARTNUM))
#pragma message("I2CPINS=" STR(I2CPINS))
@@ -67,12 +68,13 @@ static void iwdg_setup(){
int main(void){
uint32_t lastT = 0, lastS = 0;
uint8_t gotmeasurement = 0;
char inbuf[256];
sysreset();
SysTick_Config(6000, 1);
gpio_setup();
adc_setup();
usart_setup();
i2c_setup(LOW_SPEED);
iwdg_setup();
CAN_setup();
SEND("Greetings! My address is ");
@@ -86,11 +88,13 @@ int main(void){
SEND("SOFTRESET=1\n");
}
RCC->CSR |= RCC_CSR_RMVF; // remove reset flags
USB_setup();
iwdg_setup();
while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(lastT > Tms || Tms - lastT > 499){
LED_blink(LED0);
if(!noLED) LED_blink(LED0);
lastT = Tms;
// send dummy command to noone to test CAN bus
can_send_cmd(NOONE_ID, CMD_DUMMY0);
@@ -104,7 +108,7 @@ int main(void){
if(stat == CAN_FIFO_OVERRUN){
SEND("CAN bus fifo overrun occured!\n");
}else if(stat == CAN_ERROR){
LED_off(LED1);
if(!noLED) LED_off(LED1);
CAN_setup();
canerror = 1;
}
@@ -117,9 +121,19 @@ int main(void){
}else{
gotmeasurement = 0;
}
if(usartrx()){ // usart1 received data, store in in buffer
cmd_parser();
usb_proc();
uint8_t r = 0;
if((r = USB_receive(inbuf, 255))){
inbuf[r] = 0;
cmd_parser(inbuf, 1);
}
if(usartrx()){ // usart1 received data, store in in buffer
char *txt = NULL;
r = usart_getline(&txt);
txt[r] = 0;
cmd_parser(txt, 0);
}
sendbuf();
}
return 0;
}

View File

@@ -20,33 +20,115 @@
* MA 02110-1301, USA.
*
*/
#include "hardware.h"
#include "usart.h"
#include "adc.h"
#include "can.h"
#include "can_process.h"
#include "hardware.h"
#include "proto.h"
#include "sensors_manage.h"
#include "usart.h"
#include "usb.h"
#include <string.h> // strlen, strcpy(
extern volatile uint8_t canerror;
static char buff[UARTBUFSZ+1], *bptr = buff;
static uint8_t blen = 0, USBcmd = 0;
// LEDs are OFF by default
uint8_t noLED = 1;
void sendbuf(){
IWDG->KR = IWDG_REFRESH;
if(blen == 0) return;
*bptr = 0;
if(USBcmd) USB_send(buff);
else while(LINE_BUSY == usart_send(buff, blen)){IWDG->KR = IWDG_REFRESH;}
bptr = buff;
blen = 0;
}
void addtobuf(const char *txt){
IWDG->KR = IWDG_REFRESH;
int l = strlen(txt);
if(l > UARTBUFSZ){
sendbuf();
if(USBcmd) USB_send(txt);
else while(LINE_BUSY == usart_send_blocking(txt, l)){IWDG->KR = IWDG_REFRESH;}
}else{
if(blen+l > UARTBUFSZ){
sendbuf();
}
strcpy(bptr, txt);
bptr += l;
}
*bptr = 0;
blen += l;
}
void bufputchar(char ch){
if(blen > UARTBUFSZ-1){
sendbuf();
}
*bptr++ = ch;
++blen;
}
static void CANsend(uint16_t targetID, uint8_t cmd, char echo){
if(CAN_OK == can_send_cmd(targetID, cmd)){
usart_putchar(echo);
bufputchar(echo);
bufputchar('\n');
}
}
// show all ADC values
static inline void showADCvals(){
char msg[] = "ADCn=";
for(int n = 0; n < NUMBER_OF_ADC_CHANNELS; ++n){
msg[3] = n + '0';
addtobuf(msg);
printu(getADCval(n));
newline();
}
}
void cmd_parser(){
char *txt = NULL;
int16_t L = 0, ID = BCAST_ID;
L = usart_getline(&txt);
static inline void printmcut(){
SEND("MCUT=");
int32_t T = getMCUtemp();
if(T < 0){
bufputchar('-');
T = -T;
}
printu(T);
newline();
}
static inline void showUIvals(){
uint16_t *vals = getUval();
SEND("V12="); printu(vals[0]);
SEND("\nV5="); printu(vals[1]);
SEND("\nV33="); printu(vals[3]);
SEND("\nI12="); printu(vals[2]);
newline();
}
/**
* @brief cmd_parser - command parsing
* @param txt - buffer with commands & data
* @param isUSB - == 1 if data got from USB
*/
void cmd_parser(char *txt, uint8_t isUSB){
USBcmd = isUSB;
int16_t L = strlen(txt), ID = BCAST_ID;
char _1st = txt[0];
sendbuf();
if(_1st >= '0' && _1st < '8'){ // send command to Nth controller, not broadcast
if(L == 3){ // with '\n' at end!
if(_1st == '0'){
usart_putchar(txt[1]);
/*if(_1st == '0'){
bufputchar(txt[1]);
_1st = txt[1] + 'a' - 'A'; // change network command to local
newline();
}else{
bufputchar('\n');
}else */
{
ID = (CAN_ID_PREFIX & CAN_ID_MASK) | (_1st - '0');
_1st = txt[1];
}
@@ -55,6 +137,9 @@ void cmd_parser(){
}
}else if(L != 2) _1st = '?';
switch(_1st){
case 'a':
showADCvals();
break;
case 'B':
CANsend(ID, CMD_DUMMY0, _1st);
break;
@@ -93,12 +178,40 @@ void cmd_parser(){
printuhex(getCANID());
newline();
break;
case 'J':
CANsend(ID, CMD_GETMCUTEMP, _1st);
break;
case 'j':
printmcut();
break;
case 'K':
CANsend(ID, CMD_GETUIVAL, _1st);
break;
case 'k':
showUIvals();
break;
case 'L':
CANsend(ID, CMD_LOW_SPEED, _1st);
break;
case 'l':
i2c_setup(LOW_SPEED);
break;
case 'M':
CANsend(ID, CMD_CHANGE_MASTER_B, _1st);
break;
case 'm':
CANsend(ID, CMD_CHANGE_MASTER, _1st);
break;
case 'O':
noLED = 0;
SEND("LED on\n");
break;
case 'o':
noLED = 1;
LED_off(LED0);
LED_off(LED1);
SEND("LED off\n");
break;
case 'P':
CANsend(ID, CMD_PING, _1st);
break;
@@ -120,12 +233,13 @@ void cmd_parser(){
case 't':
if(!sensors_scan_mode) sensors_start();
break;
break;
case 'u':
SEND("CANERROR=");
if(canerror){
canerror = 0;
usart_putchar('1');
}else usart_putchar('0');
bufputchar('1');
}else bufputchar('0');
newline();
break;
case 'V':
@@ -139,13 +253,14 @@ void cmd_parser(){
break;
case 'z':
SEND("SSTATE0=");
usart_putchar(sensors_get_state());
printu(sensors_get_state());
newline();
break;
default: // help
SEND(
"ALL little letters - without CAN messaging\n"
"0..7 - send command to given controller (0 - this) instead of broadcast\n"
"a - get raw ADC values\n"
"B - send broadcast CAN dummy message\n"
"c - show coefficients (current)\n"
"D - send CAN dummy message to master\n"
@@ -154,8 +269,11 @@ void cmd_parser(){
"g - get last CAN address\n"
"Hh- high I2C speed\n"
"i - reinit CAN (with new address)\n"
"Jj- get MCU temperature\n"
"Kk- get U/I values\n"
"Ll- low I2C speed\n"
// "o - turn On sensors\n"
"Mm- change master id to 0 (m) / broadcast (M)\n"
"Oo- turn onboard diagnostic LEDs *O*n or *o*ff (both commands are local)\n"
"P - ping everyone over CAN\n"
"Rr- reinit I2C\n"
"Ss- Start themperature scan\n"
@@ -166,4 +284,34 @@ void cmd_parser(){
);
break;
}
sendbuf();
}
// print 32bit unsigned int
void printu(uint32_t val){
char buf[11], *bufptr = &buf[10];
*bufptr = 0;
if(!val){
*(--bufptr) = '0';
}else{
while(val){
*(--bufptr) = val % 10 + '0';
val /= 10;
}
}
addtobuf(bufptr);
}
// print 32bit unsigned int as hex
void printuhex(uint32_t val){
addtobuf("0x");
uint8_t *ptr = (uint8_t*)&val + 3;
int i, j;
for(i = 0; i < 4; ++i, --ptr){
for(j = 1; j > -1; --j){
uint8_t half = (*ptr >> (4*j)) & 0x0f;
if(half < 10) bufputchar(half + '0');
else bufputchar(half - 10 + 'a');
}
}
}

View File

@@ -24,6 +24,25 @@
#ifndef __PROTO_H__
#define __PROTO_H__
void cmd_parser();
#include "stm32f0.h"
// macro for static strings
#define SEND(str) do{addtobuf(str);}while(0)
#ifdef EBUG
#define MSG(str) do{addtobuf(__FILE__ " (L" STR(__LINE__) "): " str);}while(0)
#else
#define MSG(str)
#endif
#define newline() do{bufputchar('\n');}while(0)
extern uint8_t noLED;
void cmd_parser(char *buf, uint8_t isUSB);
void addtobuf(const char *txt);
void bufputchar(char ch);
void printu(uint32_t val);
void printuhex(uint32_t val);
void sendbuf();
#endif // __PROTO_H__

View File

@@ -23,7 +23,7 @@
#include "sensors_manage.h"
#include "can_process.h"
#include "i2c.h"
#include "usart.h"
#include "proto.h" // addtobuf, bufputchar
extern volatile uint32_t Tms;
uint8_t sensors_scan_mode = 0; // infinite scan mode
@@ -133,19 +133,14 @@ static void count_sensors(){
// procedure call each time @ resetting
static uint8_t resetproc(){
uint8_t i, ctr = 0;
//SEND("pair "); printu(curr_mul_addr);
//SEND(" : ");
for(i = 0; i < 2; ++i){
if(write_i2c(Taddr[i], TSYS01_RESET)){
//usart_putchar('0' + i);
++ctr;
sens_present[i] |= 1<<curr_mul_addr; // set bit - found
}else{ // not found
sens_present[i] &= ~(1<<curr_mul_addr); // reset bit - not found
}
}
//if(!ctr) SEND("not found");
//newline();
return 0;
}
@@ -153,46 +148,20 @@ static uint8_t resetproc(){
static uint8_t getcoefsproc(){
uint8_t i, j;
const uint8_t regs[5] = {0xAA, 0xA8, 0xA6, 0xA4, 0xA2}; // commands for coefficients
#if 0
MSG("sens_present[0]=");
printu(sens_present[0]);
SEND(", sens_present[1]=");
printu(sens_present[1]);
newline();
#endif
for(i = 0; i < 2; ++i){
if(!(sens_present[i] & (1<<curr_mul_addr))) continue; // no sensors @ given line
uint8_t err = 5;
uint16_t *coef = coefficients[curr_mul_addr][i];
#if 0
SEND("muladdr: ");
usart_putchar('0'+curr_mul_addr);
SEND(", i: ");
usart_putchar('0'+i);
newline();
#endif
for(j = 0; j < 5; ++j){
uint32_t K;
MSG("N=");
#if 0
usart_putchar('0'+j);
newline();
#endif
if(write_i2c(Taddr[i], regs[j])){
//MSG("write\n");
if(read_i2c(Taddr[i], &K, 2)){
//MSG("read: ");
#if 0
printu(K);
newline();
#endif
coef[j] = K;
--err;
}else break;
}else break;
}
if(err){ // restart all procedures if we can't get coeffs of present sensor
//MSG("Error: can't get all coefficients!\n");
sensors_on();
return 1;
}
@@ -205,23 +174,10 @@ static uint8_t msrtempproc(){
uint8_t i, j;
for(i = 0; i < 2; ++i){
if(!(sens_present[i] & (1<<curr_mul_addr))) continue; // no sensors @ given line
//MSG("Start measurement for #");
#if 0
usart_putchar('0'+curr_mul_addr);
usart_putchar('_');
usart_putchar('0'+i);
newline();
#endif
for(j = 0; j < 5; ++j){
if(write_i2c(Taddr[i], TSYS01_START_CONV)) break;
// MSG("try more\n");
if(!write_i2c(Taddr[i], TSYS01_RESET)) i2c_setup(CURRENT_SPEED); // maybe I2C restart will solve the problem?
}
/*if(j == 5){
MSG("error start monitoring, reset counter\n");
sensors_on(); // all very bad
return 1;
}*/
}
return 0;
}
@@ -233,22 +189,9 @@ static uint8_t gettempproc(){
if(!(sens_present[i] & (1<<curr_mul_addr))) continue; // no sensors @ given line
Temperatures[curr_mul_addr][i] = NO_SENSOR;
uint8_t err = 1;
#if 0
MSG("Sensor #");
usart_putchar('0'+curr_mul_addr);
usart_putchar('_');
usart_putchar('0'+i);
newline();
#endif
if(write_i2c(Taddr[i], TSYS01_ADC_READ)){
uint32_t t;
//MSG("Read\n");
if(read_i2c(Taddr[i], &t, 3) && t){
#if 0
SEND("Calc from ");
printu(t);
newline();
#endif
if(BAD_TEMPERATURE != (Temperatures[curr_mul_addr][i] = calc_t(t, i))){
err = 0;
++Ntemp_measured;
@@ -256,7 +199,6 @@ newline();
}
}
if(err){
//MSG("Can't read temperature\n");
write_i2c(Taddr[i], TSYS01_RESET);
}
}
@@ -301,8 +243,8 @@ void showcoeffs(){
for(p = 0; p < 2; ++p){
if(!(sens_present[p] & (1<<a))) continue; // no sensor
for(k = 0; k < 5; ++k){
char b[] = {'K', a+'0', p+'0', '_', k+'0', '='};
while(ALL_OK != usart_send_blocking(b, 6));
char b[] = {'K', a+'0', p+'0', '_', k+'0', '=', 0};
addtobuf(b);
printu(coefficients[a][p][k]);
newline();
}
@@ -314,11 +256,9 @@ void showcoeffs(){
void showtemperature(){
int a, p;
if(Nsens_present == 0){
//SEND("No sensors found\n");
return;
}
if(Ntemp_measured == 0){
//SEND("No right measurements\n");
return;
}
for(a = 0; a <= MUL_MAX_ADDRESS; ++a){
@@ -326,15 +266,15 @@ void showtemperature(){
if(!(sens_present[p] & (1<<a))){
continue; // no sensor
}
usart_putchar('T');
usart_putchar('0' + Controller_address);
usart_putchar('_');
bufputchar('T');
bufputchar('0' + Controller_address);
bufputchar('_');
printu(a*10+p);
usart_putchar('=');
bufputchar('=');
int16_t t = Temperatures[a][p];
if(t < 0){
t = -t;
usart_putchar('-');
bufputchar('-');
}
printu(t);
newline();
@@ -353,7 +293,6 @@ void sensors_process(){
}
switch (Sstate){
case SENS_INITING: // initialisation (restart I2C)
//MSG("init->reset\n");
i2c_setup(CURRENT_SPEED);
Sstate = SENS_RESETING;
lastSensT = Tms;
@@ -365,10 +304,8 @@ void sensors_process(){
if(sensors_scan(resetproc)){
count_sensors(); // get total amount of sensors
if(Nsens_present){
//MSG("reset->getcoeff\n");
Sstate = SENS_GET_COEFFS;
}else{ // no sensors found
//MSG("reset->off\n");
sensors_off();
}
}
@@ -376,25 +313,18 @@ void sensors_process(){
break;
case SENS_GET_COEFFS: // get coefficients
if(sensors_scan(getcoefsproc)){
//MSG("got coeffs for ");
#if 0
printu(Nsens_present);
SEND(" sensors ->start\n");
#endif
Sstate = SENS_START_MSRMNT;
}
break;
case SENS_START_MSRMNT: // send all sensors command to start measurements
if(sensors_scan(msrtempproc)){
lastSensT = Tms;
//MSG("->wait\n");
Sstate = SENS_WAITING;
Ntemp_measured = 0; // reset value of good measurements
}
break;
case SENS_WAITING: // wait for end of conversion
if(Tms - lastSensT > CONV_TIME){
//MSG("->gather\n");
Sstate = SENS_GATHERING;
}
break;
@@ -403,16 +333,6 @@ SEND(" sensors ->start\n");
lastSensT = Tms;
NsentOverCAN = 0;
Sstate = SENS_SLEEPING;
//MSG("->sleep\n");
/*
if(Nsens_present == Ntemp_measured){ // All OK, amount of T == amount of sensors
MSG("->sleep\n");
Sstate = SENS_SLEEPING;
}else{ // reinit I2C & try to start measurements again
MSG("gather error ->start\n");
i2c_setup(CURRENT_SPEED);
Sstate = SENS_START_MSRMNT;
}*/
}
break;
case SENS_SLEEPING: // wait for `SLEEP_TIME` till next measurements
@@ -424,14 +344,12 @@ MSG("gather error ->start\n");
}
if(sensors_scan_mode){ // sleep until next measurement start
if(Tms - lastSensT > SLEEP_TIME){
//MSG("sleep->start\n");
Sstate = SENS_START_MSRMNT;
}
}
}
break;
case SENS_OVERCURNT: // try to reinit all after overcurrent
//MSG("try to turn on after overcurrent\n");
sensors_on();
break;
default: // do nothing

View File

@@ -40,16 +40,16 @@ extern int16_t Temperatures[MUL_MAX_ADDRESS+1][2];
extern uint8_t sens_present[2];
typedef enum{
SENS_INITING // power on
,SENS_RESETING // discovery sensors resetting them
,SENS_GET_COEFFS // get coefficients from all sensors
,SENS_SLEEPING // wait for a time to process measurements
,SENS_START_MSRMNT // send command 2 start measurement
,SENS_WAITING // wait for measurements end
,SENS_GATHERING // collect information
,SENS_OFF // sensors' power is off by external command
,SENS_OVERCURNT // overcurrent detected @ any stage
,SENS_OVERCURNT_OFF // sensors' power is off due to continuous overcurrent
SENS_INITING // 0 power on
,SENS_RESETING // 1 discovery sensors resetting them
,SENS_GET_COEFFS // 2 get coefficients from all sensors
,SENS_SLEEPING // 3 wait for a time to process measurements
,SENS_START_MSRMNT // 4 send command 2 start measurement
,SENS_WAITING // 5 wait for measurements end
,SENS_GATHERING // 6 collect information
,SENS_OFF // 7 sensors' power is off by external command
,SENS_OVERCURNT // 8 overcurrent detected @ any stage
,SENS_OVERCURNT_OFF // 9 sensors' power is off due to continuous overcurrent
} SensorsState;
SensorsState sensors_get_state();
@@ -58,12 +58,7 @@ void sensors_process();
void sensors_off();
void sensors_on();
void sensors_start();
void showcoeffs();
void showtemperature();
#ifdef EBUG
void senstest(char cmd);
#endif
#endif // __SENSORS_MANAGE_H__

Binary file not shown.

View File

@@ -1,4 +1,4 @@
/*us
/*
* usart.c
*
* Copyright 2017 Edward V. Emelianoff <eddy@sao.ru, edward.emelianoff@gmail.com>
@@ -76,24 +76,20 @@ TXstatus usart_send_blocking(const char *str, int len){
bufovr = 0;
for(i = 0; i < len; ++i){
USARTX -> TDR = *str++;
while(!(USARTX->ISR & USART_ISR_TXE));
while(!(USARTX->ISR & USART_ISR_TXE)){IWDG->KR = IWDG_REFRESH;};
}
return ALL_OK;
}
void usart_putchar(const char ch){
while(!txrdy);
USARTX -> TDR = ch;
while(!(USARTX->ISR & USART_ISR_TXE));
void usart_send_blck(const char *str){
while(!txrdy){IWDG->KR = IWDG_REFRESH;}
bufovr = 0;
while(*str){
USARTX -> TDR = *str++;
while(!(USARTX->ISR & USART_ISR_TXE)){IWDG->KR = IWDG_REFRESH;};
}
}
void newline(){
while(!txrdy);
USARTX -> TDR = '\n';
while(!(USARTX->ISR & USART_ISR_TXE));
}
void usart_setup(){
// Nucleo's USART2 connected to VCP proxy of st-link
#if USARTNUM == 2
@@ -197,41 +193,6 @@ void usart1_isr(){
}
}
// 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];
}
}
while(LINE_BUSY == usart_send_blocking(bufa, l+bpos));
}
// print 32bit unsigned int as hex
void printuhex(uint32_t val){
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){
uint8_t half = (*ptr >> (4*j)) & 0x0f;
if(half < 10) usart_putchar(half + '0');
else usart_putchar(half - 10 + 'a');
}
}
}
#if USARTNUM == 2
void dma1_channel4_5_isr(){
if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx

View File

@@ -29,15 +29,6 @@
#define TIMEOUT_MS (1500)
#endif
// macro for static strings
#define SEND(str) do{}while(LINE_BUSY == usart_send_blocking(str, sizeof(str)-1))
#ifdef EBUG
#define MSG(str) do{SEND(__FILE__ " (L" STR(__LINE__) "): " str);}while(0)
#else
#define MSG(str)
#endif
typedef enum{
ALL_OK,
LINE_BUSY,
@@ -53,9 +44,6 @@ void usart_setup();
int usart_getline(char **line);
TXstatus usart_send(const char *str, int len);
TXstatus usart_send_blocking(const char *str, int len);
void newline();
void usart_putchar(const char ch);
void printu(uint32_t val);
void printuhex(uint32_t val);
void usart_send_blck(const char *str);
#endif // __USART_H__

182
STM32/TSYS_controller/usb.c Normal file
View File

@@ -0,0 +1,182 @@
/*
* geany_encoding=koi8-r
* usb.c - base functions for different USB types
*
* Copyright 2018 Edward V. Emelianov <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.
*
*/
#include "usb.h"
#include "usb_lib.h"
#include <string.h> // memcpy, memmove
#include "usart.h"
// incoming buffer size
#define IDATASZ (256)
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?)
static uint16_t EP1_Handler(ep_t ep){
uint8_t ep0buf[11];
if (ep.rx_flag){
EP_Read(1, ep0buf);
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;
}
// 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, &incoming_data[idatalen]);
ovfl = 0;
}else{
ep.status = SET_NAK_RX(ep.status);
ovfl = 1;
return ep.status;
}
}
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;
}
void USB_setup(){
RCC->APB1ENR |= RCC_APB1ENR_CRSEN | RCC_APB1ENR_USBEN; // enable CRS (hsi48 sync) & USB
RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB
RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48
uint32_t tmout = 16000000;
while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break; IWDG->KR = IWDG_REFRESH;}
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
CRS->CFGR &= ~CRS_CFGR_SYNCSRC;
CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source
CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim
CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only
RCC->CFGR |= RCC_CFGR_SW;
// allow RESET and CTRM interrupts
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
// clear flags
USB->ISTR = 0;
// and activate pullup
USB->BCDR |= USB_BCDR_DPPU;
NVIC_EnableIRQ(USB_IRQn);
}
void usb_proc(){
if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints
if(!usbON){ // endpoints not activated
// 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){
uint16_t l = 0, ctr = 0;
const char *p = buf;
while(*p++) ++l;
while(l){
IWDG->KR = IWDG_REFRESH;
uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l;
tx_succesfull = 0;
EP_Write(3, (uint8_t*)&buf[ctr], s);
uint32_t ctra = 1000000;
while(--ctra && tx_succesfull == 0){IWDG->KR = IWDG_REFRESH;}
l -= s;
ctr += s;
}
}
/**
* @brief USB_receive - read first received text string
* @param buf (i) - buffer for received data
* @param bufsize - its size
* @return amount of received bytes
*/
int USB_receive(char *buf, int bufsize){
if(bufsize<1 || !idatalen) return 0;
IWDG->KR = IWDG_REFRESH;
int stlen = 0, i;
for(i = 0; i < idatalen; ++i){
if(incoming_data[i] == '\n'){
stlen = i+1;
break;
}
}
if(i == idatalen || stlen == 0) return 0;
/*
char x[] = "USB got x:\n";
x[8] = '0' + stlen;
usart_send_blck(x);
usart_send_blck((char*)incoming_data);
usart_send_blck("\n");
*/
USB->CNTR = 0;
int sz = (stlen > bufsize) ? bufsize : stlen, rest = idatalen - sz;
memcpy(buf, incoming_data, sz);
buf[sz] = 0;
/*
usart_send_blck("buf:\n");
usart_send_blck((char*)buf);
usart_send_blck("\n");
*/
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(){
return usbON;
}

View File

@@ -0,0 +1,37 @@
/*
* geany_encoding=koi8-r
* usb.h
*
* Copyright 2018 Edward V. Emelianov <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 __USB_H__
#define __USB_H__
#include "hardware.h"
#define BUFFSIZE (64)
void USB_setup();
void usb_proc();
void USB_send(const char *buf);
int USB_receive(char *buf, int bufsize);
int USB_configured();
#endif // __USB_H__

View File

@@ -0,0 +1,106 @@
/*
* geany_encoding=koi8-r
* usb_defs.h
*
* Copyright 2018 Edward V. Emelianov <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 __USB_DEFS_H__
#define __USB_DEFS_H__
#include <stm32f0xx.h>
/**
* Buffers size definition
**/
// !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
#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)
#define USB_EP0_BUFSZ 64
// USB transmit buffer size (64 for PL2303)
#define USB_TXBUFSZ 64
// USB receive buffer size (64 for PL2303)
#define USB_RXBUFSZ 64
#define USB_BTABLE_BASE 0x40006000
#undef USB_BTABLE
#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE))
#define USB_ISTR_EPID 0x0000000F
#define USB_FNR_LSOF_0 0x00000800
#define USB_FNR_lSOF_1 0x00001000
#define USB_LPMCSR_BESL_0 0x00000010
#define USB_LPMCSR_BESL_1 0x00000020
#define USB_LPMCSR_BESL_2 0x00000040
#define USB_LPMCSR_BESL_3 0x00000080
#define USB_EPnR_CTR_RX 0x00008000
#define USB_EPnR_DTOG_RX 0x00004000
#define USB_EPnR_STAT_RX 0x00003000
#define USB_EPnR_STAT_RX_0 0x00001000
#define USB_EPnR_STAT_RX_1 0x00002000
#define USB_EPnR_SETUP 0x00000800
#define USB_EPnR_EP_TYPE 0x00000600
#define USB_EPnR_EP_TYPE_0 0x00000200
#define USB_EPnR_EP_TYPE_1 0x00000400
#define USB_EPnR_EP_KIND 0x00000100
#define USB_EPnR_CTR_TX 0x00000080
#define USB_EPnR_DTOG_TX 0x00000040
#define USB_EPnR_STAT_TX 0x00000030
#define USB_EPnR_STAT_TX_0 0x00000010
#define USB_EPnR_STAT_TX_1 0x00000020
#define USB_EPnR_EA 0x0000000F
#define USB_COUNTn_RX_BLSIZE 0x00008000
#define USB_COUNTn_NUM_BLOCK 0x00007C00
#define USB_COUNTn_RX 0x0000003F
#define USB_TypeDef USB_TypeDef_custom
typedef struct{
__IO uint32_t EPnR[8];
__IO uint32_t RESERVED1;
__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 ISTR;
__IO uint32_t FNR;
__IO uint32_t DADDR;
__IO uint32_t BTABLE;
__IO uint32_t LPMCSR;
__IO uint32_t BCDR;
} USB_TypeDef;
typedef struct{
__IO uint16_t USB_ADDR_TX;
__IO uint16_t USB_COUNT_TX;
__IO uint16_t USB_ADDR_RX;
__IO uint16_t USB_COUNT_RX;
} USB_EPDATA_TypeDef;
typedef struct{
__IO USB_EPDATA_TypeDef EP[8];
} USB_BtableDef;
#endif // __USB_DEFS_H__

View File

@@ -0,0 +1,532 @@
/*
* geany_encoding=koi8-r
* usb_lib.c
*
* Copyright 2018 Edward V. Emelianov <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.
*
*/
#include "proto.h"
#include "usart.h"
#include "usb_lib.h"
#include <stdint.h>
#include <string.h> // memcpy
ep_t endpoints[ENDPOINTS_NUM];
static usb_dev_t USB_Dev;
static usb_LineCoding lineCoding = {115200, 0, 0, 8};
static config_pack_t setup_packet;
static uint8_t ep0databuf[EP0DATABUF_SIZE];
static uint8_t ep0dbuflen = 0;
usb_LineCoding getLineCoding(){return lineCoding;}
// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor
#define bcdUSB_L 0x10
#define bcdUSB_H 0x01
#define bDeviceClass 0
#define bDeviceSubClass 0
#define bDeviceProtocol 0
#define bNumConfigurations 1
static const uint8_t USB_DeviceDescriptor[] = {
18, // bLength
0x01, // bDescriptorType - Device descriptor
bcdUSB_L, // bcdUSB_L - 1.10
bcdUSB_H, // bcdUSB_H
bDeviceClass, // bDeviceClass - USB_COMM
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0_BUFSZ, // bMaxPacketSize
0x7b, // idVendor_L PL2303: VID=0x067b, PID=0x2303
0x06, // idVendor_H
0x03, // idProduct_L
0x23, // idProduct_H
0x00, // bcdDevice_Ver_L
0x03, // bcdDevice_Ver_H
0x01, // iManufacturer
0x02, // iProduct
0x00, // iSerialNumber
bNumConfigurations // bNumConfigurations
};
static const uint8_t USB_DeviceQualifierDescriptor[] = {
10, //bLength
0x06, // bDescriptorType - Device qualifier
bcdUSB_L, // bcdUSB_L
bcdUSB_H, // bcdUSB_H
bDeviceClass, // bDeviceClass
bDeviceSubClass, // bDeviceSubClass
bDeviceProtocol, // bDeviceProtocol
USB_EP0_BUFSZ, // bMaxPacketSize0
bNumConfigurations, // bNumConfigurations
0x00 // Reserved
};
static const uint8_t USB_ConfigDescriptor[] = {
/*Configuration Descriptor*/
0x09, /* bLength: Configuration Descriptor size */
0x02, /* bDescriptorType: Configuration */
39, /* wTotalLength:no of returned bytes */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: Configuration value */
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
0xa0, /* bmAttributes - Bus powered, Remote wakeup */
0x32, /* MaxPower 100 mA */
/*---------------------------------------------------------------------------*/
/*Interface Descriptor */
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: Interface */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x03, /* bNumEndpoints: 3 endpoints used */
0xff, /* bInterfaceClass */
0x00, /* bInterfaceSubClass */
0x00, /* bInterfaceProtocol */
0x00, /* iInterface: */
///////////////////////////////////////////////////
/*Endpoint 1 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x81, /* bEndpointAddress IN1 */
0x03, /* bmAttributes: Interrupt */
0x0a, /* wMaxPacketSize LO: */
0x00, /* wMaxPacketSize HI: */
0x01, /* bInterval: */
/*Endpoint OUT2 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x02, /* bEndpointAddress: OUT2 */
0x02, /* bmAttributes: Bulk */
(USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
(USB_RXBUFSZ >> 8),
0x00, /* bInterval: ignore for Bulk transfer */
/*Endpoint IN3 Descriptor*/
0x07, /* bLength: Endpoint Descriptor size */
0x05, /* bDescriptorType: Endpoint */
0x83, /* bEndpointAddress IN3 */
0x02, /* bmAttributes: Bulk */
(USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */
(USB_TXBUFSZ >> 8),
0x00, /* bInterval: ignore for Bulk transfer */
};
_USB_LANG_ID_(USB_StringLangDescriptor, LANG_US);
// these descriptors are not used in PL2303 emulator!
_USB_STRING_(USB_StringSerialDescriptor, u"0");
_USB_STRING_(USB_StringManufacturingDescriptor, u"Prolific Technology Inc.");
_USB_STRING_(USB_StringProdDescriptor, u"USB-Serial Controller");
/*
* default handlers
*/
// SET_LINE_CODING
void WEAK linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){
MSG("linecoding_handler\n");
}
// SET_CONTROL_LINE_STATE
void WEAK clstate_handler(uint16_t __attribute__((unused)) val){
MSG("clstate_handler\n");
}
// SEND_BREAK
void WEAK break_handler(){
MSG("break_handler\n");
}
// handler of vendor requests
void WEAK vendor_handler(config_pack_t *packet){
if(packet->bmRequestType & 0x80){ // read
//SEND("Read");
uint8_t c;
switch(packet->wValue){
case 0x8484:
c = 2;
break;
case 0x0080:
c = 1;
break;
case 0x8686:
c = 0xaa;
break;
default:
c = 0;
}
EP_WriteIRQ(0, &c, 1);
}else{ // write ZLP
//SEND("Write");
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){
if(setup_packet.wLength < size) size = setup_packet.wLength;
EP_WriteIRQ(0, buf, size);
}
static inline void get_descriptor(){
switch(setup_packet.wValue){
case DEVICE_DESCRIPTOR:
wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor));
break;
case CONFIGURATION_DESCRIPTOR:
wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor));
break;
case STRING_LANG_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringLangDescriptor, STRING_LANG_DESCRIPTOR_SIZE_BYTE);
break;
case STRING_MAN_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringManufacturingDescriptor, USB_StringManufacturingDescriptor.bLength);
break;
case STRING_PROD_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringProdDescriptor, USB_StringProdDescriptor.bLength);
break;
case STRING_SN_DESCRIPTOR:
wr0((const uint8_t *)&USB_StringSerialDescriptor, USB_StringSerialDescriptor.bLength);
break;
case DEVICE_QUALIFIER_DESCRIPTOR:
wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]);
break;
default:
WRITEDUMP("UNK_DES");
break;
}
}
static uint8_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured)
static inline void std_d2h_req(){
uint16_t status = 0; // bus powered
switch(setup_packet.bRequest){
case GET_DESCRIPTOR:
get_descriptor();
break;
case GET_STATUS:
EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered
break;
case GET_CONFIGURATION:
WRITEDUMP("GET_CONFIGURATION");
EP_WriteIRQ(0, &configuration, 1);
break;
default:
WRITEDUMP("80:WR_REQ");
break;
}
}
static inline void std_h2d_req(){
switch(setup_packet.bRequest){
case SET_ADDRESS:
// new address will be assigned later - after acknowlegement or request to host
USB_Dev.USB_Addr = setup_packet.wValue;
break;
case SET_CONFIGURATION:
// Now device configured
USB_Dev.USB_Status = USB_CONFIGURE_STATE;
configuration = setup_packet.wValue;
break;
default:
WRITEDUMP("0:WR_REQ");
break;
}
}
/*
bmRequestType: 76543210
7 direction: 0 - host->device, 1 - device->host
65 type: 0 - standard, 1 - class, 2 - vendor
4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other
*/
/**
* 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
uint8_t reqtype = setup_packet.bmRequestType & 0x7f;
uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0;
if ((ep.rx_flag) && (ep.setup_flag)){
switch(reqtype){
case STANDARD_DEVICE_REQUEST_TYPE: // standard device request
if(dev2host){
std_d2h_req();
}else{
std_h2d_req();
// send ZLP
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){
// send ZLP
EP_WriteIRQ(0, (uint8_t *)0, 0);
epstatus = SET_NAK_RX(epstatus);
epstatus = SET_VALID_TX(epstatus);
}else{
WRITEDUMP("02:WR_REQ");
}
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){
case GET_LINE_CODING:
EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding));
break;
case SET_LINE_CODING: // omit this for next stage, when data will come
break;
case SET_CONTROL_LINE_STATE:
clstate_handler(setup_packet.wValue);
break;
case SEND_BREAK:
break_handler();
break;
default:
WRITEDUMP("undef control req");
}
if(!dev2host) 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);
if(setup_packet.bRequest == SET_LINE_CODING){
//WRITEDUMP("SET_LINE_CODING");
linecoding_handler((usb_LineCoding*)ep0databuf);
}
}
// Close transaction
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
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;
}
// 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
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');
}
#endif
return epstatus;
}
#undef WRITEDUMP
static uint16_t lastaddr = USB_EP0_BASEADDR;
/**
* Endpoint initialisation
* !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!!
* @param number - EP num (0...7)
* @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT)
* @param txsz - transmission buffer size @ USB/CAN buffer
* @param rxsz - reception buffer size @ USB/CAN buffer
* @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)){
if(number >= ENDPOINTS_NUM) 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
USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA);
USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1;
if(rxsz & 1 || rxsz > 992) return 3; // wrong rx buffer size
uint16_t countrx = 0;
if(rxsz < 64) countrx = rxsz / 2;
else{
if(rxsz & 0x1f) return 3; // should be multiple of 32
countrx = 31 + rxsz / 32;
}
USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr;
endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr);
lastaddr += txsz;
USB_BTABLE->EP[number].USB_COUNT_TX = 0;
USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr;
endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr);
lastaddr += rxsz;
// buffer size: Table127 of RM
USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10;
endpoints[number].func = func;
return 0;
}
// standard IRQ handler
void usb_isr(){
if (USB->ISTR & USB_ISTR_RESET){
// Reinit registers
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM;
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 = USB_EP0_BASEADDR; // roll back to beginning of buffer
EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler);
// clear address, leave only enable bit
USB->DADDR = USB_DADDR_EF;
// state is default - wait for enumeration
USB_Dev.USB_Status = USB_DEFAULT_STATE;
}
if(USB->ISTR & USB_ISTR_CTR){
// EP number
uint8_t n = USB->ISTR & USB_ISTR_EPID;
// copy status register
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
endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter
// 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(n == 0){ // control endpoint
if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack
memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(setup_packet));
ep0dbuflen = 0;
// 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
// 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;
}
}
/**
* Write data to EP buffer (called from IRQ handler)
* @param number - EP number
* @param *buf - array with data
* @param size - its size
*/
void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){
uint8_t i;
if(size > USB_TXBUFSZ) size = USB_TXBUFSZ;
uint16_t N2 = (size + 1) >> 1;
// the buffer is 16-bit, so we should copy data as it would be uint16_t
uint16_t *buf16 = (uint16_t *)buf;
for (i = 0; i < N2; i++){
endpoints[number].tx_buf[i] = buf16[i];
}
USB_BTABLE->EP[number].USB_COUNT_TX = size;
}
/**
* Write data to EP buffer (called outside IRQ handler)
* @param number - EP number
* @param *buf - array with data
* @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;
}
/*
* Copy data from EP buffer into user buffer area
* @param *buf - user array for data
* @return amount of data read
*/
int EP_Read(uint8_t number, uint8_t *buf){
int n = endpoints[number].rx_cnt;
if(n){
for(int i = 0; i < n; ++i)
buf[i] = endpoints[number].rx_buf[i];
}
return n;
}
// USB status
uint8_t USB_GetState(){
return USB_Dev.USB_Status;
}

View File

@@ -0,0 +1,202 @@
/*
* geany_encoding=koi8-r
* usb_lib.h
*
* Copyright 2018 Edward V. Emelianov <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 __USB_LIB_H__
#define __USB_LIB_H__
#include <wchar.h>
#include "usb_defs.h"
#define EP0DATABUF_SIZE (64)
// Max EP amount (EP0 + other used)
#define ENDPOINTS_NUM 4
// bmRequestType & 0x7f
#define STANDARD_DEVICE_REQUEST_TYPE 0
#define STANDARD_ENDPOINT_REQUEST_TYPE 2
#define VENDOR_REQUEST_TYPE 0x40
#define CONTROL_REQUEST_TYPE 0x21
// bRequest, standard; for bmRequestType == 0x80
#define GET_STATUS 0x00
#define GET_DESCRIPTOR 0x06
#define GET_CONFIGURATION 0x08
// for bmRequestType == 0
#define CLEAR_FEATURE 0x01
#define SET_FEATURE 0x03 // unused
#define SET_ADDRESS 0x05
#define SET_DESCRIPTOR 0x07 // unused
#define SET_CONFIGURATION 0x09
// for bmRequestType == 0x81, 1 or 0xB2
#define GET_INTERFACE 0x0A // unused
#define SET_INTERFACE 0x0B // unused
#define SYNC_FRAME 0x0C // unused
#define VENDOR_REQUEST 0x01 // unused
// Class-Specific Control Requests
#define SEND_ENCAPSULATED_COMMAND 0x00 // unused
#define GET_ENCAPSULATED_RESPONSE 0x01 // unused
#define SET_COMM_FEATURE 0x02 // unused
#define GET_COMM_FEATURE 0x03 // unused
#define CLEAR_COMM_FEATURE 0x04 // unused
#define SET_LINE_CODING 0x20
#define GET_LINE_CODING 0x21
#define SET_CONTROL_LINE_STATE 0x22
#define SEND_BREAK 0x23
// control line states
#define CONTROL_DTR 0x01
#define CONTROL_RTS 0x02
// wValue
#define DEVICE_DESCRIPTOR 0x100
#define CONFIGURATION_DESCRIPTOR 0x200
#define STRING_LANG_DESCRIPTOR 0x300
#define STRING_MAN_DESCRIPTOR 0x301
#define STRING_PROD_DESCRIPTOR 0x302
#define STRING_SN_DESCRIPTOR 0x303
#define DEVICE_QUALIFIER_DESCRIPTOR 0x600
// 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)))
// USB state: uninitialized, addressed, ready for use
#define USB_DEFAULT_STATE 0
#define USB_ADRESSED_STATE 1
#define USB_CONFIGURE_STATE 2
// EP types
#define EP_TYPE_BULK 0x00
#define EP_TYPE_CONTROL 0x01
#define EP_TYPE_ISO 0x02
#define EP_TYPE_INTERRUPT 0x03
#define LANG_US (uint16_t)0x0409
#define _USB_STRING_(name, str) \
static const struct name \
{ \
uint8_t bLength; \
uint8_t bDescriptorType; \
uint16_t bString[(sizeof(str) - 2) / 2]; \
\
} \
name = {sizeof(name), 0x03, str}
#define _USB_LANG_ID_(name, lng_id) \
\
static const struct name \
{ \
uint8_t bLength; \
uint8_t bDescriptorType; \
uint16_t bString; \
\
} \
name = {0x04, 0x03, lng_id}
#define STRING_LANG_DESCRIPTOR_SIZE_BYTE (4)
// EP0 configuration packet
typedef struct {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} config_pack_t;
// endpoints state
typedef struct __ep_t{
uint16_t *tx_buf; // transmission buffer address
uint8_t *rx_buf; // reception buffer address
uint16_t (*func)(); // endpoint action function
uint16_t status; // status flags
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
typedef struct {
uint8_t USB_Status;
uint16_t USB_Addr;
}usb_dev_t;
typedef struct {
uint32_t dwDTERate;
uint8_t bCharFormat;
#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();
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 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, 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__