mirror of
https://github.com/eddyem/stm32samples.git
synced 2025-12-06 10:45:11 +03:00
F0 testbrd: I2C, DAC
This commit is contained in:
parent
20f4205459
commit
348d3f4dca
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
194
F0-nolib/F0_testbrd/i2c.c
Normal 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, ®, 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
47
F0-nolib/F0_testbrd/i2c.h
Normal 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__
|
||||||
@ -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.
@ -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(®[channel], buf+1);
|
return chPWM(®[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");
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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(){
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user