F0 testbrd: I2C, DAC

This commit is contained in:
Edward Emelianov 2021-07-02 23:11:53 +03:00
parent 20f4205459
commit 348d3f4dca
12 changed files with 447 additions and 47 deletions

View File

@ -22,11 +22,12 @@
* @brief ADC_array - array for ADC channels with median filtering: * @brief ADC_array - array for ADC channels with median filtering:
* 0 - Rvar * 0 - Rvar
* 1 - Rvar/2 * 1 - Rvar/2
* 2 - internal Tsens * 2 - AIN5/DAC_OUT1
* 3 - Vref * 3 - internal Tsens
* 4 - Vref
*/ */
#define CHTSENS (2) #define CHTSENS (3)
#define CHVREF (3) #define CHVREF (4)
uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9]; uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
/** /**
@ -55,7 +56,7 @@ uint16_t getADCval(int nch){
} }
// get voltage @input nch (1/100V) // get voltage @input nch (1/100V)
uint32_t getADCvoltate(int nch){ uint32_t getADCvoltage(int nch){
uint32_t v = getADCval(nch); uint32_t v = getADCval(nch);
v *= getVdd(); v *= getVdd();
v /= 0xfff; // 12bit ADC v /= 0xfff; // 12bit ADC

View File

@ -19,12 +19,13 @@
#define ADC_H #define ADC_H
#include "stm32f0.h" #include "stm32f0.h"
#define NUMBER_OF_ADC_CHANNELS (4) #define NUMBER_OF_ADC_CHANNELS (5)
extern uint16_t ADC_array[]; extern uint16_t ADC_array[];
int32_t getMCUtemp(); int32_t getMCUtemp();
uint32_t getVdd(); uint32_t getVdd();
uint16_t getADCval(int nch); uint16_t getADCval(int nch);
uint32_t getADCvoltate(int nch); uint32_t getADCvoltage(int nch);
#endif // ADC_H #endif // ADC_H

View File

@ -23,6 +23,7 @@
#include "adc.h" #include "adc.h"
#include "hardware.h" #include "hardware.h"
#include "proto.h"
void iwdg_setup(){ void iwdg_setup(){
uint32_t tmout = 16000000; uint32_t tmout = 16000000;
@ -50,21 +51,18 @@ void iwdg_setup(){
static inline void gpio_setup(){ static inline void gpio_setup(){
// here we turn on clocking for all periph. // here we turn on clocking for all periph.
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMAEN; RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_DMAEN;
// Set LEDS (PA6-8, PB0/1) as Oun & AF (PWM) // Set LEDS (PA6-8, PB0/1) as Out & AF (PWM); PA0,1,5 - AIN, PA4 - DAC
GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7 | GPIO_MODER_MODER8)) | GPIOA->MODER = GPIO_MODER_MODER0_AI | GPIO_MODER_MODER1_AI | GPIO_MODER_MODER4_AI |
GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF | GPIO_MODER_MODER8_AF; GPIO_MODER_MODER5_AI | GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF | GPIO_MODER_MODER8_AF;
GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER0 | GPIO_MODER_MODER1)) | GPIOB->MODER = GPIO_MODER_MODER0_AF | GPIO_MODER_MODER1_AF;
GPIO_MODER_MODER0_AF | GPIO_MODER_MODER1_AF;
// alternate functions: PA6-8: TIM3CH1,2 and TIM1_CH1 (AF1, AF1, AF2) // alternate functions: PA6-8: TIM3CH1,2 and TIM1_CH1 (AF1, AF1, AF2)
// PB0-1: TIM3CH3,4 (AF1, AF1) // PB0-1: TIM3CH3,4 (AF1, AF1),
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) | GPIOA->AFR[0] = (1 << (6 * 4)) | (1 << (7 * 4));
(1 << (6 * 4)) | (1 << (7 * 4)); GPIOA->AFR[1] = (2 << (0 * 4));
GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH0)) | GPIOB->AFR[0] = (1 << (0 * 4)) | (1 << (1 * 4));
(2 << (0 * 4));
GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL0 | GPIO_AFRL_AFRL1)) |
(1 << (0 * 4)) | (1 << (1 * 4));
} }
// Setup ADC and DAC
static inline void adc_setup(){ static inline void adc_setup(){
uint16_t ctr = 0; // 0xfff0 - more than 1.3ms uint16_t ctr = 0; // 0xfff0 - more than 1.3ms
// Enable clocking // Enable clocking
@ -90,15 +88,15 @@ static inline void adc_setup(){
do{ do{
ADC1->CR |= ADC_CR_ADEN; ADC1->CR |= ADC_CR_ADEN;
}while ((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0); }while ((ADC1->ISR & ADC_ISR_ADRDY) == 0 && ++ctr < 0xfff0);
// configure ADC // configure ADC to generate a triangle wave on DAC1_OUT synchronized by TIM6 HW trigger
/* (1) Select HSI14 by writing 00 in CKMODE (reset value) */ /* (1) Select HSI14 by writing 00 in CKMODE (reset value) */
/* (2) Select the continuous mode */ /* (2) Select the continuous mode */
/* (3) Select CHSEL0,1 - ADC inputs, 16,17 - t. sensor and vref */ /* (3) Select CHSEL0,1,5 - 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 */ /* (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) */ /* (5) Wake-up the VREFINT and Temperature sensor (only for VBAT, Temp sensor and VRefInt) */
// ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */ // ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */
ADC1->CFGR1 |= ADC_CFGR1_CONT; /* (2)*/ ADC1->CFGR1 |= ADC_CFGR1_CONT; /* (2)*/
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; /* (3)*/ ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL5 | ADC_CHSELR_CHSEL16 | ADC_CHSELR_CHSEL17; /* (3)*/
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */ ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */
ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; /* (5) */ ADC->CCR |= ADC_CCR_TSEN | ADC_CCR_VREFEN; /* (5) */
// configure DMA for ADC // configure DMA for ADC
@ -118,6 +116,27 @@ static inline void adc_setup(){
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC; /* (6) */ 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) */ DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */
ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversions */ ADC1->CR |= ADC_CR_ADSTART; /* start the ADC conversions */
// DAC
/* (1) Enable the peripheral clock of the DAC */
/* (2) Configure WAVEx at 10,
Configure mask amplitude for ch1 (MAMP1) at 1011 for a 4095-bits amplitude
enable the DAC ch1, disable buffer on ch1,
and select TIM6 as trigger by keeping 000 in TSEL1 */
RCC->APB1ENR |= RCC_APB1ENR_DACEN; /* (1) */
DAC->CR |= DAC_CR_WAVE1_1
| DAC_CR_MAMP1_3 | DAC_CR_MAMP1_1 | DAC_CR_MAMP1_0
| DAC_CR_BOFF1 | DAC_CR_TEN1 | DAC_CR_EN1; /* (2) */
// configure the Timer 6 to generate an external trigger on TRGO each microsecond
/* (1) Enable the peripheral clock of the TIM6 */
/* (2) Configure MMS=010 to output a rising edge at each update event */
/* (3) Select PCLK/2 i.e. 48MHz/2=24MHz */
/* (4) Set one update event each 1 microsecond */
/* (5) Enable TIM6 */
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; /* (1) */
TIM6->CR2 |= TIM_CR2_MMS_1; /* (2) */
TIM6->PSC = 1; /* (3) */
TIM6->ARR = (uint16_t)24; /* (4) */
TIM6->CR1 |= TIM_CR1_CEN; /* (5) */
} }
static inline void pwm_setup(){ static inline void pwm_setup(){

194
F0-nolib/F0_testbrd/i2c.c Normal file
View File

@ -0,0 +1,194 @@
/*
* geany_encoding=koi8-r
* i2c.c
*
* Copyright 2017 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 "hardware.h"
#include "i2c.h"
#include "proto.h"
#include "usb.h"
I2C_SPEED curI2Cspeed = LOW_SPEED;
extern volatile uint32_t Tms;
static uint32_t cntr;
volatile uint8_t I2C_scan_mode = 0; // == 1 when I2C is in scan mode
static uint8_t i2caddr = I2C_ADDREND; // not active
void i2c_setup(I2C_SPEED speed){
if(speed >= CURRENT_SPEED){
speed = curI2Cspeed;
}else{
curI2Cspeed = speed;
}
I2C1->CR1 = 0;
/*
* GPIO Resources: I2C1_SCL - PB6, I2C1_SDA - PB7 (AF1)
*/
GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7)) |
1 << (6 * 4) | 1 << (7 * 4);
GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) |
GPIO_MODER_MODER6_AF | GPIO_MODER_MODER7_AF;
GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7; // both open-drain outputs
// I2C
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // timing
RCC->CFGR3 |= RCC_CFGR3_I2C1SW; // use sysclock for timing
if(speed == LOW_SPEED){ // 10kHz
// PRESC=B, SCLDEL=4, SDADEL=2, SCLH=0xC3, SCLL=0xB0
I2C1->TIMINGR = (0xB<<28) | (4<<20) | (2<<16) | (0xC3<<8) | (0xB0);
}else if(speed == HIGH_SPEED){ // 100kHz
I2C1->TIMINGR = (0xB<<28) | (4<<20) | (2<<16) | (0x12<<8) | (0x11);
}else{ // VERYLOW_SPEED - the lowest speed by STM register: 5.8kHz (presc = 16-1 = 15; )
I2C1->TIMINGR = (0xf<<28) | (4<<20) | (2<<16) | (0xff<<8) | (0xff);
}
I2C1->CR1 = I2C_CR1_PE;
}
/**
* write command byte to I2C
* @param addr - device address (TSYS01_ADDR0 or TSYS01_ADDR1)
* @param data - bytes to write
* @param nbytes - amount of bytes to write
* @param stop - to set STOP
* @return 0 if error
*/
static uint8_t write_i2cs(uint8_t addr, uint8_t *data, uint8_t nbytes, uint8_t stop){
cntr = Tms;
I2C1->CR1 = 0; // clear busy flag
I2C1->ICR = 0x3f38; // clear all errors
I2C1->CR1 = I2C_CR1_PE;
while(I2C1->ISR & I2C_ISR_BUSY){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
USND("Line busy\n");
return 0; // check busy
}}
cntr = Tms;
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 = nbytes << 16 | addr;
if(stop) I2C1->CR2 |= I2C_CR2_AUTOEND; // autoend
// now start transfer
I2C1->CR2 |= I2C_CR2_START;
for(int i = 0; i < nbytes; ++i){
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;
USND("NAK\n");
return 0;
}
if(Tms - cntr > I2C_TIMEOUT){
USND("Timeout\n");
return 0;
}
}
I2C1->TXDR = data[i]; // send data
}
// wait for data gone
while(I2C1->ISR & I2C_ISR_BUSY){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){break;}
}
return 1;
}
uint8_t write_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes){
return write_i2cs(addr, data, nbytes, 1);
}
/**
* read nbytes of data from I2C line
* `data` should be an array with at least `nbytes` length
* @return 1 if all OK, 0 if NACK or no device found
*/
static uint8_t read_i2cb(uint8_t addr, uint8_t *data, uint8_t nbytes, uint8_t busychk){
if(busychk){
cntr = Tms;
while(I2C1->ISR & I2C_ISR_BUSY){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
USND("Line busy\n");
return 0; // check busy
}}
}
cntr = Tms;
while(I2C1->CR2 & I2C_CR2_START){
IWDG->KR = IWDG_REFRESH;
if(Tms - cntr > I2C_TIMEOUT){
USND("No start\n");
return 0; // check start
}}
// read N bytes
I2C1->CR2 = (nbytes<<16) | addr | 1 | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN;
I2C1->CR2 |= I2C_CR2_START;
uint8_t i;
for(i = 0; i < nbytes; ++i){
cntr = Tms;
while(!(I2C1->ISR & I2C_ISR_RXNE)){ // wait for data
IWDG->KR = IWDG_REFRESH;
if(I2C1->ISR & I2C_ISR_NACKF){
I2C1->ICR |= I2C_ICR_NACKCF;
USND("NAK\n");
return 0;
}
if(Tms - cntr > I2C_TIMEOUT){
USND("Timeout\n");
return 0;
}
}
*data++ = I2C1->RXDR;
}
return 1;
}
uint8_t read_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes){
return read_i2cb(addr, data, nbytes, 1);
}
// read register reg
uint8_t read_i2c_reg(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t nbytes){
if(!write_i2cs(addr, &reg, 1, 0)) return 0;
return read_i2cb(addr, data, nbytes, 0);
}
void i2c_init_scan_mode(){
i2caddr = 0;
I2C_scan_mode = 1;
}
// return 1 if next addr is active & return in as `addr`
// if addresses are over, return 1 and set addr to I2C_NOADDR
// if scan mode inactive, return 0 and set addr to I2C_NOADDR
int i2c_scan_next_addr(uint8_t *addr){
*addr = i2caddr;
if(i2caddr == I2C_ADDREND){
*addr = I2C_ADDREND;
I2C_scan_mode = 0;
return 0;
}
if(!read_i2c_reg((i2caddr++)<<1, 0, NULL, 0)) return 0;
return 1;
}

47
F0-nolib/F0_testbrd/i2c.h Normal file
View File

@ -0,0 +1,47 @@
/*
* This file is part of the F0testbrd project.
* Copyright 2021 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/>.
*/
#pragma once
#ifndef I2C_H__
#define I2C_H__
#include "stm32f0.h"
#define I2C_ADDREND (0x80)
typedef enum{
VERYLOW_SPEED,
LOW_SPEED,
HIGH_SPEED,
CURRENT_SPEED
} I2C_SPEED;
extern I2C_SPEED curI2Cspeed;
extern volatile uint8_t I2C_scan_mode;
// timeout of I2C bus in ms
#define I2C_TIMEOUT (100)
void i2c_setup(I2C_SPEED speed);
uint8_t read_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes);
uint8_t read_i2c_reg(uint8_t addr, uint8_t reg, uint8_t *data, uint8_t nbytes);
uint8_t write_i2c(uint8_t addr, uint8_t *data, uint8_t nbytes);
void i2c_init_scan_mode();
int i2c_scan_next_addr(uint8_t *addr);
#endif // I2C_H__

View File

@ -21,11 +21,15 @@
#include "adc.h" #include "adc.h"
#include "hardware.h" #include "hardware.h"
#include "usart.h" #include "i2c.h"
#include "proto.h" #include "proto.h"
#include "usart.h"
#include "usb.h" #include "usb.h"
#include "usb_lib.h" #include "usb_lib.h"
// ADC value threshold for meaning it is new
#define ADCthreshold (20)
volatile uint32_t Tms = 0; volatile uint32_t Tms = 0;
/* Called when systick fires */ /* Called when systick fires */
@ -33,6 +37,9 @@ void sys_tick_handler(void){
++Tms; ++Tms;
} }
volatile uint8_t ADCmon = 0; // ==1 to monitor ADC (change PWM of LEDS & show current value)
uint16_t oldADCval = 0;
int main(void){ int main(void){
uint32_t lastT = 0; uint32_t lastT = 0;
sysreset(); sysreset();
@ -48,9 +55,33 @@ int main(void){
while (1){ while (1){
IWDG->KR = IWDG_REFRESH; // refresh watchdog IWDG->KR = IWDG_REFRESH; // refresh watchdog
if(lastT > Tms || Tms - lastT > 499){ if(lastT > Tms || Tms - lastT > 499){
if(ADCmon){
uint16_t v = getADCval(0);
int32_t d = v - oldADCval;
if(d < -ADCthreshold || d > ADCthreshold){
oldADCval = v;
printADCvals();
v >>= 2; // 10 bits
TIM3->CCR1 = TIM3->CCR2 = TIM3->CCR3 = 0xff; TIM3->CCR4 = 0;
if(v >= 0x300) TIM3->CCR4 = v - 0x300;
else if(v >= 0x200) TIM3->CCR3 = v - 0x200;
else if(v >= 0x100){ TIM3->CCR2 = v - 0x100; TIM3->CCR3 = 0; }
else{ TIM3->CCR1 = v; TIM3->CCR2 = TIM3->CCR3 = 0; }
}
}
lastT = Tms; lastT = Tms;
transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s transmit_tbuf(); // non-blocking transmission of data from UART buffer every 0.5s
} }
if(I2C_scan_mode){
uint8_t addr;
int ok = i2c_scan_next_addr(&addr);
if(addr == I2C_ADDREND) USND("Scan ends\n");
else if(ok){
USB_sendstr(uhex2str(addr));
USND(" ("); USB_sendstr(u2str(addr));
USND(") - found device\n");
}
}
usb_proc(); usb_proc();
char *txt; char *txt;
if((txt = get_USB())){ if((txt = get_USB())){

Binary file not shown.

View File

@ -17,6 +17,7 @@
*/ */
#include "adc.h" #include "adc.h"
#include "i2c.h"
#include "proto.h" #include "proto.h"
#include "usart.h" #include "usart.h"
#include "usb.h" #include "usb.h"
@ -29,7 +30,7 @@ void USB_sendstr(const char *str){
USB_send((const uint8_t*)str, l); USB_send((const uint8_t*)str, l);
} }
static char *chPWM(volatile uint32_t *reg, char *buf){ static inline char *chPWM(volatile uint32_t *reg, char *buf){
char *lbuf = buf; char *lbuf = buf;
lbuf = omit_spaces(lbuf); lbuf = omit_spaces(lbuf);
char cmd = *lbuf; char cmd = *lbuf;
@ -50,14 +51,14 @@ static char *chPWM(volatile uint32_t *reg, char *buf){
return "OK"; return "OK";
} }
static char *TIM3pwm(char *buf){ static inline char *TIM3pwm(char *buf){
uint8_t channel = *buf - '1'; uint8_t channel = *buf - '1';
if(channel > 3) return "Wrong channel number"; if(channel > 3) return "Wrong channel number";
volatile uint32_t *reg = &TIM3->CCR1; volatile uint32_t *reg = &TIM3->CCR1;
return chPWM(&reg[channel], buf+1); return chPWM(&reg[channel], buf+1);
} }
static char *getPWMvals(){ static inline char *getPWMvals(){
USND("TIM1CH1: "); USB_sendstr(u2str(TIM1->CCR1)); USND("TIM1CH1: "); USB_sendstr(u2str(TIM1->CCR1));
USND("\nTIM3CH1: "); USB_sendstr(u2str(TIM3->CCR1)); USND("\nTIM3CH1: "); USB_sendstr(u2str(TIM3->CCR1));
USND("\nTIM3CH2: "); USB_sendstr(u2str(TIM3->CCR2)); USND("\nTIM3CH2: "); USB_sendstr(u2str(TIM3->CCR2));
@ -67,7 +68,7 @@ static char *getPWMvals(){
return NULL; return NULL;
} }
static char *USARTsend(char *buf){ static inline char *USARTsend(char *buf){
uint32_t N; uint32_t N;
if(buf == getnum(buf, &N)) return "Point number of USART"; if(buf == getnum(buf, &N)) return "Point number of USART";
if(N < 1 || N > USARTNUM) return "Wrong USART number"; if(N < 1 || N > USARTNUM) return "Wrong USART number";
@ -77,20 +78,103 @@ static char *USARTsend(char *buf){
return "OK"; return "OK";
} }
static uint8_t i2cinited = 0;
static inline char *setupI2C(char *buf){
buf = omit_spaces(buf);
if(*buf < '0' || *buf > '2') return "Wrong speed";
i2c_setup(*buf - '0');
i2cinited = 1;
return "OK";
}
static uint8_t I2Caddress = 0;
static uint8_t I2Cdata[12];
static inline char *saI2C(char *buf){
uint32_t addr;
if(!getnum(buf, &addr) || addr > 0x7f) return "Wrong address";
I2Caddress = (uint8_t) addr << 1;
USND("I2Caddr="); USB_sendstr(uhex2str(addr)); USND("\n");
return "OK";
}
static inline void rdI2C(char *buf){
uint32_t N;
char *nxt = getnum(buf, &N);
if(!nxt || buf == nxt || N > 0xff){
USND("Bad register number\n");
return;
}
buf = nxt;
uint8_t reg = N;
nxt = getnum(buf, &N);
if(!nxt || buf == nxt || N > 12){
USND("Bad length\n");
return;
}
if(!read_i2c_reg(I2Caddress, reg, I2Cdata, N)){
USND("Error reading I2C\n");
return;
}
if(N == 0){ USND("OK"); return; }
USND("Register "); USB_sendstr(uhex2str(reg)); USND(":\n");
for(uint32_t i = 0; i < N; ++i){
if(i < 10) USND(" ");
USB_sendstr(u2str(i)); USND(": "); USB_sendstr(uhex2str(I2Cdata[i]));
USND("\n");
}
}
static inline char *wrI2C(char *buf){
uint8_t N = 0;
uint32_t D;
char *nxt;
while((nxt = getnum(buf, &D)) && nxt != buf && N < 12){
buf = nxt;
I2Cdata[N++] = (uint8_t) D&0xff;
USND("add byte: "); USB_sendstr(uhex2str(D&0xff)); USND("\n");
}
USND("Send "); USB_sendstr(u2str(N)); USND(" bytes\n");
if(!write_i2c(I2Caddress, I2Cdata, N)) return "Error writing I2C";
return "OK";
}
static inline char *DAC_chval(char *buf){
uint32_t D;
char *nxt = getnum(buf, &D);
if(!nxt || nxt == buf || D > 4095) return "Wrong DAC amplitude\n";
DAC->DHR12R1 = D;
return "OK";
}
const char *helpstring = const char *helpstring =
"'+'/'-'[num] - increase/decrease TIM1ch1 PWM by 1 or `num`\n" "+/-[num] - increase/decrease TIM1ch1 PWM by 1 or `num`\n"
"1..4'+'/'-'[num] - increase/decrease TIM3chN PWM by 1 or `num`\n" "1..4'+'/'-'[num] - increase/decrease TIM3chN PWM by 1 or `num`\n"
"'g' - get PWM values\n" "A - get ADC values\n"
"'A' - get ADC values\n" "dx - change DAC lowcal to x\n"
"'L' - send long string over USB\n" "g - get PWM values\n"
"'R' - software reset\n" "i0..3 - setup I2C with lowest..highest speed (5.8, 10 and 100kHz)\n"
"'S' - send short string over USB\n" "Ia addr - set I2C address\n"
"'Ux' - send string to USARTx (1..3)\n" "Iw bytes - send bytes (hex/dec/oct/bin) to I2C\n"
"'T' - MCU temperature\n" "Ir reg n - read n bytes from I2C reg\n"
"'V' - Vdd\n" "Is - scan I2C bus\n"
"'W' - test watchdog\n" "L - send long string over USB\n"
"m - monitor ADC on/off\n"
"R - software reset\n"
"S - send short string over USB\n"
"Ux str - send string to USARTx (1..3)\n"
"T - MCU temperature\n"
"V - Vdd\n"
"W - test watchdog\n"
; ;
void printADCvals(){
USND("AIN0: "); USB_sendstr(u2str(getADCval(0)));
USND(" ("); USB_sendstr(u2str(getADCvoltage(0)));
USND("/100 V)\nAIN1: "); USB_sendstr(u2str(getADCval(1)));
USND(" ("); USB_sendstr(u2str(getADCvoltage(1)));
USND("/100 V)\nAIN5: "); USB_sendstr(u2str(getADCval(2)));
USND(" ("); USB_sendstr(u2str(getADCvoltage(2)));
USND("/100 V)\n");
}
const char *parse_cmd(char *buf){ const char *parse_cmd(char *buf){
// "long" commands // "long" commands
switch(*buf){ switch(*buf){
@ -103,6 +187,21 @@ const char *parse_cmd(char *buf){
case '3': case '3':
case '4': case '4':
return TIM3pwm(buf); return TIM3pwm(buf);
break;
case 'd':
return DAC_chval(buf + 1);
case 'i':
return setupI2C(buf + 1);
break;
case 'I':
if(!i2cinited) return "Init I2C first";
buf = omit_spaces(buf + 1);
if(*buf == 'a') return saI2C(buf + 1);
else if(*buf == 'r'){ rdI2C(buf + 1); return NULL; }
else if(*buf == 'w') return wrI2C(buf + 1);
else if(*buf == 's') i2c_init_scan_mode();
else return "Command should be 'Ia', 'Iw', 'Ir' or 'Is'\n";
break;
case 'U': case 'U':
return USARTsend(buf + 1); return USARTsend(buf + 1);
break; break;
@ -114,17 +213,19 @@ const char *parse_cmd(char *buf){
return getPWMvals(); return getPWMvals();
break; break;
case 'A': case 'A':
USND("ADC0: "); USB_sendstr(u2str(getADCval(0))); printADCvals();
USND(" ("); USB_sendstr(u2str(getADCvoltate(0)));
USND("/100 V)\nADC1: "); USB_sendstr(u2str(getADCval(1)));
USND(" ("); USB_sendstr(u2str(getADCvoltate(1)));
USND("/100 V)\n");
break; break;
case 'L': case 'L':
USND("Very long test string for USB (it's length is more than 64 bytes).\n" USND("Very long test string for USB (it's length is more than 64 bytes).\n"
"This is another part of the string! Can you see all of this?\n"); "This is another part of the string! Can you see all of this?\n");
return "Long test sent"; return "Long test sent";
break; break;
case 'm':
ADCmon = !ADCmon;
USND("Monitoring is ");
if(ADCmon) USND("on\n");
else USND("off\n");
break;
case 'R': case 'R':
USND("Soft reset\n"); USND("Soft reset\n");
//SEND("Soft reset\n"); //SEND("Soft reset\n");

View File

@ -19,12 +19,18 @@
#ifndef PROTO_H__ #ifndef PROTO_H__
#define PROTO_H__ #define PROTO_H__
#include "stm32f0.h"
#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0) #define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0)
extern volatile uint8_t ADCmon;
void USB_sendstr(const char *str); void USB_sendstr(const char *str);
char *get_USB(); char *get_USB();
const char *parse_cmd(char *buf); const char *parse_cmd(char *buf);
void printADCvals();
char *u2str(uint32_t val); char *u2str(uint32_t val);
char *i2str(int32_t i); char *i2str(int32_t i);
char *uhex2str(uint32_t val); char *uhex2str(uint32_t val);

View File

@ -139,6 +139,7 @@ void usart_setup(){
GPIO_MODER_MODER10_AF | GPIO_MODER_MODER11_AF; GPIO_MODER_MODER10_AF | GPIO_MODER_MODER11_AF;
GPIOB->AFR[1] = (GPIOB->AFR[1] & ~(GPIO_AFRH_AFRH2 | GPIO_AFRH_AFRH3)) | GPIOB->AFR[1] = (GPIOB->AFR[1] & ~(GPIO_AFRH_AFRH2 | GPIO_AFRH_AFRH3)) |
4 << (2 * 4) | 4 << (3 * 4); // PB10, PB11 4 << (2 * 4) | 4 << (3 * 4); // PB10, PB11
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
#endif #endif
for(int i = 0; i < USARTNUM; ++i){ for(int i = 0; i < USARTNUM; ++i){
USARTs[i]->ICR = 0xffffffff; // clear all flags USARTs[i]->ICR = 0xffffffff; // clear all flags
@ -210,7 +211,6 @@ static void usart_IRQ(int usartno){
#endif #endif
} }
} }
USARTX->ICR = 0xffffffff;
} }
void usart1_isr(){ void usart1_isr(){

View File

@ -27,7 +27,7 @@ uint8_t getI2Caddr(){
return i2caddr; return i2caddr;
} }
void init_scan_mode(){ void i2c_init_scan_mode(){
i2caddr = 0; i2caddr = 0;
scanmode = 1; scanmode = 1;
} }
@ -35,7 +35,7 @@ void init_scan_mode(){
// return 1 if next addr is active & return in as `addr` // return 1 if next addr is active & return in as `addr`
// if addresses are over, return 1 and set addr to I2C_NOADDR // if addresses are over, return 1 and set addr to I2C_NOADDR
// if scan mode inactive, return 0 and set addr to I2C_NOADDR // if scan mode inactive, return 0 and set addr to I2C_NOADDR
int scan_next_addr(uint8_t *addr){ int i2c_scan_next_addr(uint8_t *addr){
*addr = i2caddr; *addr = i2caddr;
if(!scanmode || i2caddr == I2C_ADDREND){ if(!scanmode || i2caddr == I2C_ADDREND){
*addr = I2C_ADDREND; *addr = I2C_ADDREND;

View File

@ -27,8 +27,8 @@ extern uint8_t scanmode;
uint8_t getI2Caddr(); uint8_t getI2Caddr();
void init_scan_mode(); void i2c_init_scan_mode();
int scan_next_addr(uint8_t *addr); int i2c_scan_next_addr(uint8_t *addr);
int read_reg(uint8_t reg, uint8_t *val, uint8_t N); int read_reg(uint8_t reg, uint8_t *val, uint8_t N);
int write_reg(uint8_t reg, uint8_t val); int write_reg(uint8_t reg, uint8_t val);