stm32l152 as I2C slave not acknowledging address - i2c

Im using two stm32l152 discovery boars. One is configured as master and the other as slave. I have acknowladge enabled on both of them, but when the master sends the address the slave doesn't send the ack bit at the 9 clock pulse. The ports are set to alternate function 4 and to open drain. I am using external 4.7k pullup resistors to 3.3V. I've checked all the registers multiple times and I don't know why the slave doesn't recognizes it's address.
This is the output from the logic analyser
D3 is the start bit from the master
D4 is the addres matched bit on the slave.
This is the slave code:
#define USE_STDPERIPH_DRIVER
#include "stm32l1xx.h"
#include "stm32l1xx_conf.h"
//Quick hack, approximately 1ms delay
void ms_delay(int ms)
{
while (ms> 0) {
volatile int x = 5971;
while (x> 0) {
x--;
}
ms--;
}
}
#define SCL 8
#define SDA 9
int main(void)
{
RCC->AHBENR |= (0x1 << 1);
//set port to alternate function
GPIOB->MODER &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
GPIOB->MODER |= ((0x2 << (2 * SCL)) | (0x2 << (2 * SDA)) | (0x1 << (2 * 5)));
GPIOB->OTYPER |= ((1 << SCL) | (1 << SDA)); //set output PB6 and PB7 to open drain
//set PB6 and PB7 to no pullup no pulldown
GPIOB->PUPDR &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] &= ~((0b1111 << (4 * 0)) | (0b1111 << (4 * 1)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] |= ((0b0100 << (4 * 0)) | (0b0100 << (4 * 1)));
RCC->APB1ENR |= (1 << 21);
//reset I2C
I2C1->CR1 |= (1 << 15);
ms_delay(1);
I2C1->CR1 &= ~(1 << 15);
I2C1->CR2 |= 0b001000; //peripheral clock set to 8MHz
I2C1->CR1 |= (1 << 10); //ACK enabled
I2C1->OAR1 |= (0x05 << 1); //setting primary address
I2C1->CR1 |= 1; //I2C peripheral enabled when configuration is done
for (;;) {
if ((I2C1->SR1&(1 << 1)) != 0) {
GPIOB->ODR |= (1 << 5);
}
else {
GPIOB->ODR &= ~(1 << 5);
}
}
}
This is the master code:
#define USE_STDPERIPH_DRIVER
#include "stm32l1xx.h"
#include "stm32l1xx_conf.h"
#define SCL 8
#define SDA 9
int main(void)
{
RCC->AHBENR |= (0x1 << 1);
//set port to alternate function
GPIOB->MODER &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
GPIOB->MODER |= ((0x2 << (2 * SCL)) | (0x2 << (2 * SDA)) | (0x1 << (2 * 5)));
//set output PB6 and PB7 to open drain
GPIOB->OTYPER |= ((1 << SCL) | (1 << SDA));
//set PB6 and PB7 to no pullup no pulldown
GPIOB->PUPDR &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] &= ~((0b1111 << (4 * 0)) | (0b1111 << (4 * 1)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] |= ((0b0100 << (4 * 0)) | (0b0100 << (4 * 1)));
I2C1->CR1 |= (1 << 15);
I2C1->CR1 &= ~(1 << 15);
RCC->APB1ENR |= (1 << 21);
I2C1->CR2 |= 0x08; //peripheral clock set to 8MHz
I2C1->CCR |= 0x28; //
I2C1->TRISE |= 0x09;
I2C1->CR1 |= (1 << 10); //ACK enabled
I2C1->CR1 |= 1; //I2C peripheral enabled when configuration is done
I2C1->CR1 |= (1 << 8); //generate start condition (master mode)
for (;;) {
//check start condition
if ((I2C1->SR1&(1 << 0)) != 0) {
GPIOB->ODR |= (1 << 5);
I2C1->DR = 0x0b << 0; //send slave addres
}
else {
GPIOB->ODR &= ~(1 << 5);
}
if ((I2C1->SR1&(1 << 1)) != 0) {
GPIOB->ODR |= (1 << 5);
}
else {
GPIOB->ODR &= ~(1 << 5);
}
}
}
Im compiling with arm-none-eabi-gcc and using the stsw-stm32077 librarys from stm

The problem with the code is that you have to set the ack bit after the peripheral is enabled, if you do it before, the ack bit gets automatically reset.

Related

STM32 SPI with ADXL372

I'm trying to read device id of ADXL372 with stm32 spi. But i'm always getting FF. If I change the address, still reads FF. I tried various configurations but I don't think it is the issue. I thought maybe my clock is so fast (170MHz) and i changed but it also didn't solve the problem. I don't understand what I'm doing wrong.
#include "main.h"
#include "SysClockConf.h"
char rxb;
uint8_t print=0;
uint16_t reading=0, value1=0, value2=0;
uint8_t bastir=0;
float deneme=0;
void Delay(uint32_t x)
{
while(x)
{
x--;
}
}
void transmit_string(char *s ){
//while( !( USART1->ISR & USART_ISR_TXE ) ) {};
while(*s){
USART1->TDR = *s ;
while( !( USART1->ISR & USART_ISR_TC ) );
s++;}
}
void transmit_char(char c){
//while( !( USART1->ISR & USART_ISR_TXE ) ) {};
USART1->TDR = c ;
while( !( USART1->ISR & USART_ISR_TC ) );
}
void transmit_number(uint8_t n){
//while( !( USART1->ISR & USART_ISR_TXE ) ) {};
USART1->TDR = n ;
while( !( USART1->ISR & USART_ISR_TC ) );
}
void spi_transmit_number(uint8_t n, uint8_t m){
GPIOA->BRR |= (GPIO_BRR_BR15);
while( !( SPI1->SR & SPI_SR_TXE ) ) {};
*(uint8_t*) & SPI1->DR = n ;
while( !( SPI1->SR & SPI_SR_TXE ) ) {};
*(uint8_t*) & SPI1->DR = m ;
GPIOA->BSRR |= (GPIO_BSRR_BS15);
}
uint8_t spi_read_number(uint8_t n){
GPIOA->BRR |= (GPIO_BRR_BR15);
while( !( SPI1->SR & SPI_SR_TXE ) ) {};
*(uint8_t*) & SPI1->DR = n ; //n = (adress shifted left one time + RW')
while( !( SPI1->SR & SPI_SR_RXNE ) ) {};
uint8_t result = SPI1->DR;
GPIOA->BSRR |= (GPIO_BSRR_BS15);
return result;
}
int k=0;
void Initialization(){
// Enable peripheral clocks: GPIOA, USART1, SPI1, ADC1 and TIMER4.
RCC->APB2ENR |= ( RCC_APB2ENR_USART1EN ) | ( RCC_APB2ENR_SPI1EN );
RCC->AHB2ENR |= ( RCC_AHB2ENR_GPIOAEN ) | ( RCC_AHB2ENR_GPIOBEN ) | ( RCC_AHB2ENR_ADC12EN );
RCC->APB1ENR1 |= RCC_APB1ENR1_TIM4EN;
// Configure pins PB3 (SPI1_CLK), PA15 (SPI1_CS), PB5 (SPI1_MOSI) and PB4 (SPI1_MISO) for SPI (AF5).
GPIOA->MODER |=(GPIO_MODER_MODE15_0);
GPIOA->MODER &= ~(GPIO_MODER_MODE15_1);
GPIOB->MODER &= ~(GPIO_MODER_MODE3_0);
GPIOB->MODER |= (GPIO_MODER_MODE3_1);
GPIOB->MODER &= ~(GPIO_MODER_MODE4_0);
GPIOB->MODER |= (GPIO_MODER_MODE4_1);
GPIOB->MODER &= ~(GPIO_MODER_MODE5_0);
GPIOB->MODER |= (GPIO_MODER_MODE5_1);
GPIOA->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR15) ;
GPIOB->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR3) | (GPIO_OSPEEDER_OSPEEDR4) | (GPIO_OSPEEDER_OSPEEDR4);
GPIOB->AFR[0] |= (0b0101<<GPIO_AFRL_AFSEL3_Pos) | (0b0101<<GPIO_AFRL_AFSEL4_Pos) | (0b0101<<GPIO_AFRL_AFSEL5_Pos);
// Configure pins A9 (TX), A10 (RX) for USART1 (AF7).
GPIOA->MODER &= ~(GPIO_MODER_MODE9_0);
GPIOA->MODER |= GPIO_MODER_MODE9_1;
GPIOA->MODER &= ~(GPIO_MODER_MODE10_0);
GPIOA->MODER |= (GPIO_MODER_MODE10_1);
GPIOA->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR9) | (GPIO_OSPEEDER_OSPEEDR10);
GPIOA->PUPDR = (GPIOA->PUPDR & ~(GPIO_PUPDR_PUPD9)) & ~(GPIO_PUPDR_PUPD10);
GPIOA->AFR[1] |= (0b0111<<GPIO_AFRH_AFSEL9_Pos) | (0b0111<<GPIO_AFRH_AFSEL10_Pos);
USART1->CR1 &= ~(USART_CR1_UE); //Disable UART1
//USART1->PRESC = 0b0001;
// Set the baud rate to 115200.
uint32_t SystemCoreClock = 170000000;
uint16_t uartdiv = SystemCoreClock / 115200;
USART1->BRR = uartdiv;
//Enable the USART peripheral.
USART1->CR1 |= ( USART_CR1_RE | USART_CR1_TE);
USART1->CR1 |= USART_CR1_RXNEIE;
USART1->CR1 |= USART_CR1_UE;
SPI1->CR1 &= ~(SPI_CR1_SPE); //Disable SPI1
SPI1->CR1 |= (0b111<<SPI_CR1_BR_Pos);; //Baud rate control fp/256
SPI1->CR1 |= (SPI_CR1_CPOL); //Clock polarity
SPI1->CR1 |= (SPI_CR1_CPHA); //Clock phase
SPI1->CR1 &= ~(SPI_CR1_RXONLY); //Disable receive only mode
SPI1->CR1 &= ~(SPI_CR1_BIDIMODE); //2-line unidirectional mode enabled
SPI1->CR1 &= ~(SPI_CR1_LSBFIRST); //MSB first mode enabled
SPI1->CR1 |= (SPI_CR1_SSM); //Software slave management enabled
SPI1->CR2 |= (SPI_CR2_SSOE); //MCU is set as master. The NSS pin is managed by the hardware.
SPI1->CR1 |= (SPI_CR1_MSTR); //Master configuration
SPI1->CR1 |= (SPI_CR1_SPE); //Enable SPI1
GPIOA->BSRR |= (GPIO_BSRR_BS15);
}
int main(void) {
HAL_Init();
SystemClock_Config();
Initialization();
spi_transmit_number(0x7E , 0x03); //0x3F => 126 (shift left and add 0 for write) power control adress //Full bandwidth measurement mode.
while ( 1 ) {
Delay(20000000);
reading=spi_read_number(0x01);
transmit_number(reading);
}
}

ADC results change but input voltage is same. STM32 - Proteus

I can't figure out how to properly set up an AD convertor for my college project.
I am supposed to use TRGO to trigger the conversion and I am trying to do it using TIM3. Every time I call ADC_Init I get the result but it differs depending on the PWM signal which does not have anything to do with it, I am trying to change the CCR of the PWM signal according to the measure of ADC. Any help on how to properly do this? Thank you!
#include <stdio.h>
#include "stm32f103x6.h"
volatile int adc_dr;
void ADC_General_Init(ADC_TypeDef * ADCx){
ADCx->CR2 |= ADC_CR2_ADON; // ukljucivanje ADC (izlazak iz rezima power-down) - ADON set
delay(20);
//kalibracija
ADCx->CR2 |= ADC_CR2_CAL;
while ((ADCx->CR2 & ADC_CR2_CAL)==ADC_CR2_CAL);
// iskljucivanje ADC dok se ne podese svi parametri (usteda energije) - ADON reset
ADCx->CR2 &= ~ADC_CR2_ADON;
ADCx->CR2 &= ~ADC_CR2_CONT; // CONT = 0: Single conversion mode - jedna konverzija
// ukljucivanje internog temperaturnog senzora i referentnog napona (strana 235)
ADCx->CR2 |= ADC_CR2_TSVREFE; // TSVREFE bit mpra biti setovan da dozvoli oba interna kanala: ADCx_IN16 (temperature sensor) and ADCx_IN17 (VREFINT) conversion.
// podesavanje konverzije jednog kanala u regularnoj grupi (strana 247)
ADCx->SQR1 &= ~ADC_SQR1_L; // setovanje bitova L[3:0]=0000: 1 konverzija, ADC_SQR1
// odredjivanje kanala 1 (Channel 1) za (prvu) konverziju u regularnoj grupi (strana 249)
ADCx->SQR3 &= ~ADC_SQR3_SQ1; // brisanje bitova
ADCx->SQR3 |= (1U << ADC_SQR3_SQ1_Pos); // setovanje bitova SQ1[4:0] u ADC_SQR3 registru - SQ1 = Channel 1; prvi kanal je u trecem registru
//"Pos" kaze da upisujem 1 (ovde) u bit (pozicija) gde pocinje SQ1 - bit 0;
//Bits 4:0 SQ1[4:0]: first conversion in regular sequence
// hardversko okidanje konverzije (strana 241)
ADCx->CR2 &= ~ADC_CR2_EXTSEL;
ADCx->CR2 |= (0b100U << ADC_CR2_EXTSEL_Pos); // EXTSEL[2:0] = 100: Timer 3 TRGO event
/*----------------ili----------------------
ADC1 -> CR2 &= ~ADC_CR2_EXTSEL;
ADC1 -> CR2 |= ADC_CR2_EXTSEL_2;
---------------------------------------------*/
ADC1 -> CR2 |= ADC_CR2_EXTTRIG; // 1: Conversion on external event enabled (strana 241)
ADCx->CR2 |= ADC_CR2_ADON;// ukljucivanje ADC
}
void ADC_GPIO_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // uključivanje takta za GPIO Port A
// strana 26 u STM32F103_Datasheet.pdf
GPIOA->CRL &= ~(GPIO_CRL_MODE1 | GPIO_CRL_CNF1); // brisanje podešavanja za PA6
GPIOA->CRL |= (GPIO_CRL_MODE1_0 | GPIO_CRL_CNF1_0); //input mode - 00: Analog mode
}
void ADC_Init(void) {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // ukljucivanje ADC1 clock-a
ADC_GPIO_Init();
ADC_General_Init(ADC1);
ADC1->CR1 |= ADC_CR1_EOCIE; // omogucivanje prekida (strana 240)
// postavlja se signal EOC: End of conversion
NVIC_SetPriority(ADC1_IRQn, 1); // dodela prioriteta na 1
//NVIC->ISER[0] |= NVIC_ISER_SETENA_18;
//NVIC_EnableIRQ(ADC1_2_IRQn); // drugi nacin
NVIC_EnableIRQ(ADC1_IRQn); // dozvola prekida ADC 1 & 2 - ista prekidna rutina broj 18 (strana 199)
}
void ADC1_2_IRQHandler(void) {
uint16_t statReg = (ADC1->SR & 0xFFFFU); // citanje statusnog registra
if ((statReg & ADC_SR_EOC) == ADC_SR_EOC) {
adc_dr = (ADC1 -> DR & 0xFFFFU); //cuvamo vrednost data registra u neku promenljivu
//TIM2->CCR4 = adc_dr/10; // treba menjati ovo deljenje
// delimo kako bismo dobili srazmernu promenu
delay(10);
ispisbroja(adc_dr);
delay(1000);
if(adc_dr <=1045){
TIM2->CCR4 = 999;
//ispisbroja(TIM2->CCR4);
}
else if( adc_dr >= 1084){
TIM2->CCR4 = 0;
//ispisbroja(TIM2->CCR4);
}
else{
TIM2->CCR4 = (int)999-(adc_dr-1045)*27,75;
//ispisbroja(TIM2->CCR4);
}
}
}
void TIM3_IRQHandler(void){
ADC_Init();
TIM3 -> SR &= ~TIM_SR_UIF;
}
void adtim1(void){
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable the peripheral clock of GPIO Port A
// Hocemo da koristimo tajmer TIM3, u rezimu Toggle Output
//TIM2->CR1 &= ~TIM_CR1_CEN;
// Enable timer 2 clock
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// Counting direction: 0 = up-counting, 1 = down-counting
//TIM2->CR1 &= ~TIM_CR1_DIR;
TIM3->CR2 &= ~TIM_CR2_MMS; // brisanje master mode selection bitova
TIM3->CR2 |= TIM_CR2_MMS_2; // setovanje OC1REF as trigger output TRGO (OC1REF=100)
// Clock prescaler (16 bits, up to 65,535)
TIM3->PSC = 7999;
//Auto-reload: up-counting (0-->ARR), down-counting (ARR-->e
TIM3->ARR = 2000;
//Upisujemo vrednost u Capture/Compare Register 1 i time podesavamo sirinu impulsa,
// tj. izlaz ce biti 1, dok je vrednost brojaca manja od vrednosti u CCR4
TIM3->CCR2 = 50;
//TIM2->CCR3 = 90;
// Output compare se podešava u registru TIMx_CCMR1 - Capture/Compare Mode Register (za kanale 1 i 2), ili TIMx_CCMR2 (za kanale 3 i 4)
// Polje OC3M[2:0], 011: Toggle - OC4REF toggles when TIMx_CNT=TIMx_CCR4.
TIM3->CCMR1 &= ~TIM_CCMR1_OC2M; // Prvo brisemo bitove za to polje
TIM3->CCMR1 |= (0b110 << TIM_CCMR1_OC2M_Pos); // Upisujemo vrednost 011 od pozicije na kojoj pocinje polje TIM_CCMR2_OC4M
//TIM3->CCMR1 |= 0b01 << TIM_CCMR1_CC2S_Pos;
//TIM3->CCMR2 &= ~TIM_CCMR2_OC4PE;
// Select output polarity: 0 = active high, 1 = active Low
TIM3->CCER &= ~TIM_CCER_CC2P; //OC4 active high
TIM3->CCER |= TIM_CCER_CC2P;
// Enable output for channel 1 , CC4E: Capture/Compare 1 output enable
TIM3->CCER |= TIM_CCER_CC2E; // 1: On - OC4 signal is output on the corresponding output pin.
//TIM3->SMCR |= 0b110 << TIM_SMCR_SMS_Pos;
//TIM3->SMCR |= 0b110 << TIM_SMCR_TS_Pos;
/*
TIM2->CCMR2 &= ~TIM_CCMR2_OC3M; // KANAL 3
TIM2->CCMR2 |= (0b011 << TIM_CCMR2_OC3M_Pos); // Upisujemo vrednost 011 od pozicije na kojoj pocinje polje TIM_CCMR2_OC4M
TIM2->CCMR2 &= ~TIM_CCMR2_OC3PE;
// Select output polarity: 0 = active high, 1 = active Low
TIM2->CCER &= ~TIM_CCER_CC3P; //OC4 active high
// Enable output for channel 1 , CC4E: Capture/Compare 1 output enable
TIM2->CCER |= TIM_CCER_CC3E; // 1: On - OC4 signal is output on the corresponding output pin. KANAL 3
*/
// Enable timer 2
//TIM2->CR1 |= (0b01 << TIM_CR1_CMS_Pos);
TIM3->CR1 &= ~TIM_CR1_ARPE;
TIM3->CR1 |= TIM_CR1_CEN;
TIM3->DIER |=TIM_DIER_UIE; //Update Interrupt Enable
TIM3 -> SR &= ~TIM_SR_UIF; //Update Interrupt Flag
//TIM3->DIER |=TIM_DIER_TIE; //Update Interrupt Enable
//TIM3 -> SR &= ~TIM_SR_TIF; //Update Interrupt Flag
NVIC_EnableIRQ(TIM3_IRQn); //Interrupt Set-Enable Register
__enable_irq(); //Enable Interrupt
}

STM32F4077 is not starting PLL (PLLRDY bit is not set)

I try to initialize a clock system with HSE source, but the PLL is not getting ready (PLLRDY bit is not set), during debugging I figured out an infinite loop on that condition
while(!(RCC->CR & RCC_CR_PLLRDY));
but the code is actually good, my groupmate wrote it and checked. just in case write it below.
#include "stm32f4xx.h" // Device header
void MCO_Init(void);
int main(void)
{
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY;
RCC->CR |= RCC_CR_HSEON; //????? (8)
while(!(RCC->CR & RCC_CR_HSERDY));
RCC->CFGR &= ~RCC_CFGR_PPRE2_Msk;
RCC->CFGR |= 0b100 << RCC_CFGR_PPRE2_Pos; //APB2 AHB/2
RCC->CFGR &= ~RCC_CFGR_PPRE1_Msk;
RCC->CFGR |= 0b101 << RCC_CFGR_PPRE1_Pos; //APB1 AHB/4
RCC->PLLCFGR |= RCC_PLLCFGR_PLLSRC; //HSE —- PLL
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLM_Msk;
RCC->PLLCFGR |= 8 << RCC_PLLCFGR_PLLM_Pos; // /8
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLN_Msk;
RCC->PLLCFGR |= 336 << RCC_PLLCFGR_PLLN_Pos;// *336
RCC->PLLCFGR &= ~RCC_PLLCFGR_PLLQ_Msk;
RCC->PLLCFGR |= 2 << RCC_PLLCFGR_PLLQ_Pos; // /2 PLL = 168
RCC->CR |= RCC_CR_PLLON;
while(!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR |= RCC_CFGR_SW_1;
RCC->CFGR &= ~RCC_CFGR_SW_0; // PLL —- AHB
while(!((RCC->CFGR & RCC_CFGR_SWS_1) && (RCC->CFGR |= RCC_CFGR_SW_0)));
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; //Enable Clock for PORTD
GPIOD->MODER |= GPIO_MODER_MODE15_0; //Outpet Mode
GPIOD->OTYPER &=~ GPIO_OTYPER_OT15; //Push-Pull
GPIOD->OSPEEDR |= GPIO_OSPEEDR_OSPEED15_0; //Medium Speed
GPIOD->MODER |= GPIO_MODER_MODE13_0; //Output Mode
GPIOD->OTYPER &=~ GPIO_OTYPER_OT13; //Push-Pull
GPIOD->OSPEEDR |= GPIO_OSPEEDR_OSPEED13_0; //Medium Speed
while (1)
{
GPIOD->BSRR |= GPIO_BSRR_BS15;
for (int i = 0; i < 2000000; i ++);
GPIOD->BSRR |= GPIO_BSRR_BR15;
GPIOD->BSRR |= GPIO_BSRR_BS13;
for (int i = 0; i < 2000000; i ++);
GPIOD->BSRR |= GPIO_BSRR_BR13;
}
}
Could anyone help me to figure out how to fix it?((((

2 stm32 adress does not match in proteus

I am trying to communicate 2 STM32 with I2C.My configuration is as followed:
7-bit addressing mode (no dual address, only OAR1)
100khz speed
ACK enabled (on slave)
ACK disabled (on master, since only 1 byte is transferred between master/slave at any time)
on both master/slave, datasheet says GPIOB (PB6) as SCL as AF and GPIOB (PB7) as SDA as AF but PB8 and PB9 becomes logic 1 in Proteus so I use PB8 and PB9.Adress does not match.Could it be because of Proteus?
Master code:
#include "stm32f10x.h" // Device header
#include "delay.h"
void pinConfig(void);
void i2c_Master_Config(void);
void sendAdress();
int main() {
pinConfig();
i2c_Master_Config();
sendAdress();
while(1) {}
}
void pinConfig() {
RCC->APB1ENR |= 1<<21;//Enable I2C 1 clock
RCC->APB2ENR |= 1<<2;//Enable GPIOA clock
RCC->APB2ENR |= 1<<3;//Enable GPIOB clock
RCC->APB2ENR |= 1<<0;//Enable AFIO clock
GPIOB->CRH |= 0x000000FF; //SCL ve SDA AF Open Drain SCL => PB8
SDA =>PB9
}
void i2c_Master_Config() {
RCC->APB1ENR |= 1<<21; //I2C 1 Clock Enable.
I2C1->CR1 |= (1 << 15);
I2C1->CR1 &= ~(1 << 15);
I2C1->CR2 |= 0x08; //36 Mhz peripheral clock.
I2C1->CCR = 0x28; //100 khz clock
I2C1->TRISE = 0x09; //1/8MHZ= 125 ns => 1000ns/125ns =8 => 8+1=9
I2C1->CR1 |= (1<<0); //Peripheral enable.
}
void sendAdress() {
volatile int temp;
I2C1->CR1 |= 1<<8; //START bit.
while(!(I2C1->SR1 & (1<<0))); //wait until start flag is set
I2C1->DR = 0x0B; //7 bit adress.
while(!(I2C1->SR1 & (1<<1))); //wait until addr flag is set
temp = I2C1->SR2; //clear addr flag.
}
Slave code:
#include "stm32f10x.h" // Device header
void pinConfig(void);
void i2c_Slave_Config(void);
uint8_t data;
void I2C1_EV_IRQHandler() {
volatile int temp;
if(I2C1->SR1 &(1<<1)) { //wait until addr flag is set
temp = I2C1->SR1; //clear addr
temp = I2C1->SR2; //clear addr
GPIOA->BRR |= 1<<3;
}
}
int main() {
pinConfig();
i2c_Slave_Config();
while(1) {}
}
void pinConfig() {
RCC->APB1ENR |= 1<<21; //I2C 1 Clock enable.
RCC->APB2ENR |= 1<<2; //Enable GPIOA clock
RCC->APB2ENR |= 1<<3; //Enable GPIOB clock
RCC->APB2ENR |= 1<<0; //Enable AFIO clock
GPIOA->CRL |= 0x00002000; //PA3 led.
GPIOB->CRH |= 0x000000FF; //SCL ve SDA AF Open Drain SCL => PB8 SDA =>PB9
GPIOA->BSRR |= 1<<3; //Turn off the led.
}
void i2c_Slave_Config() {
RCC->APB1ENR |= 1<<21; //I2C 1 Clock Enable.
I2C1->CR1 |= (1 << 15);
I2C1->CR1 &= ~(1 << 15);
I2C1->CR2 |= 0x08;
I2C1->CCR = 0x28; //100 khz clock
I2C1->OAR1 &= ~(1<<15); //7-bit slave adress.
I2C1->CR2 |= 1<<9; //Interrupt enable.
NVIC->ISER[0] |= 1<<31; //i2c1 interrupt enable.
I2C1->OAR1 = (0x05 << 1); //Slave adress
I2C1->CR1 |= (1<<0); //Peripheral enable.
I2C1->CR1 |= 1<<10; //ACK bit.
}

STM32F303: ADC with DMA only works a few times

I am currently working with a Nucleo-64 board that has the STM32F303RE chip. For programming I use the Arduino IDE with the STM32 packages. I want to avoid HAL for now because I think it is rather confusing when you have to learn the registers and the library functions at the same time.
I want to be able to sample 4 input signals parallel at 5.1 Msps (max of the F303). My plan was to keep the ADC running. Then, when I want to take the samples, I reset the DMA flags and set the counter (CNDTR-Register) to the ammount of samples I want to capture.
The following part shows my attemp to achieve this. It is basically almost working, but only a limited amount of times. How often it works seems to depend on random sleep values which I enter at certain parts in the programm.
For example: If I enter a delay of 10ms after the takeSamples()-function, the programm will work for 41 cycles of the main loop - then it gets stuck.
When it gets stuck it does the following: The DMA-CNDTR register only gets reduced by one value, then it just stays there. So the programm is waiting for the register value to become zero, but this never happens. The ADC is sampling the whole time, I can read the ADC data registers just fine.
Does anyone have an idea what could be causing the DMA to stop transfering data after a certain amount of times?
Here are the relevant parts of the program:
void setup() {
Serial.begin(57600);
// Enable clocks
RCC->AHBENR |= (1 << 17); // GPIOA
RCC->AHBENR |= (1 << 18); // GPIOB
// Set ADC pins to analog input
GPIOA->MODER |= (0b11 << 0); // PA0 for ADC1
GPIOA->MODER |= (0b11 << 8); // PA4 for ADC2
GPIOB->MODER |= (0b11 << 2); // PB1 for ADC3
GPIOB->MODER |= (0b11 << 24); // PB1 for ADC4
initClock();
DMA_init();
ADC_init();
// Start conversion
ADC1->CR |= (1 << 2);
ADC3->CR |= (1 << 2);
}
void initClock()
{
FLASH->ACR |= (0b10 << 0); // add two wait states
RCC->CR |= (1 << 18); // Bypass HSE, use external clock signal from STLink instead
RCC->CR &= ~(1 << 24); // turn off PLL
delay(100);
RCC->CFGR |= (0b0000 << 4); // Do not divide system clock
RCC->CFGR |= (0b0111 << 18); // PLL multiply = 9
RCC->CFGR |= (0b10 << 15); // use HSE as PLL source
RCC->CFGR |= (1 << 10); // not divided
delay(100);
RCC->CR |= (1 << 24); // turn on PLL
delay(100);
}
void ADC_init(void) {
RCC->CFGR2 |= (0b10000 << 4); // Prescaler
RCC->CFGR2 |= (0b10000 << 9); // Prescaler
RCC->AHBENR |= (1 << 28); // turn on ADC12 clock
RCC->AHBENR |= (1 << 29); // turn on ADC34 clock
// Set ADC clock
ADC12_COMMON->CCR |= (0b01 << 16); // 0b01
ADC34_COMMON->CCR |= (0b01 << 16); // 0b01
// disable the ADC
ADC1->CR &= ~(1 << 0);
ADC2->CR &= ~(1 << 0);
ADC3->CR &= ~(1 << 0);
ADC4->CR &= ~(1 << 0);
// enable the ADC voltage regulator
ADC1->CR &= ~(1 << 29);
ADC2->CR &= ~(1 << 29);
ADC3->CR &= ~(1 << 29);
ADC4->CR &= ~(1 << 29);
ADC1->CR |= (1 << 28);
ADC2->CR |= (1 << 28);
ADC3->CR |= (1 << 28);
ADC4->CR |= (1 << 28);
// start ADC calibration cycle
ADC1->CR |= (1 << 31);
// wait for calibration to complete
while (ADC1->CR & (1 << 31));
// start ADC calibration cycle
ADC2->CR |= (1 << 31);
// wait for calibration to complete
while (ADC2->CR & (1 << 31));
// start ADC calibration cycle
ADC3->CR |= (1 << 31);
// wait for calibration to complete
while (ADC3->CR & (1 << 31));
// start ADC calibration cycle
ADC4->CR |= (1 << 31);
// wait for calibration to complete
while (ADC4->CR & (1 << 31));
// enable the ADC
ADC1->CR |= (1 << 0);
ADC2->CR |= (1 << 0);
ADC3->CR |= (1 << 0);
ADC4->CR |= (1 << 0);
while (!(ADC1->ISR & (1 << 0)));
while (!(ADC2->ISR & (1 << 0)));
while (!(ADC3->ISR & (1 << 0)));
while (!(ADC4->ISR & (1 << 0)));
// Select ADC Channels
ADC1->SQR1 = (1 << 6);
ADC2->SQR1 = (1 << 6);
ADC3->SQR1 = (1 << 6);
ADC4->SQR1 = (3 << 6);
// Set sampling time for regular group 1
ADC1->SMPR1 |= (0b000 << 3); // 0b000 -> 1.5 clock cycles, shortest available sampling time
ADC2->SMPR1 |= (0b000 << 3);
ADC3->SMPR1 |= (0b000 << 3);
ADC4->SMPR1 |= (0b000 << 3);
// Regular sequence settings
ADC1->SQR1 |= (0b0000 << 0); // One conversion in the regular sequence
ADC2->SQR1 |= (0b0000 << 0);
ADC3->SQR1 |= (0b0000 << 0);
ADC4->SQR1 |= (0b0000 << 0);
// Enable continuous conversion mode
ADC1->CFGR |= (1 << 13); // Master ADC1 + ADC2
ADC3->CFGR |= (1 << 13); // Master ADC3 + ADC4
ADC12_COMMON->CCR |= (0b00110 << 0);
ADC34_COMMON->CCR |= (0b00110 << 0);
// DMA mode
ADC12_COMMON->CCR |= (0 << 13); // 0 -> One Shot; 1 -> Circular
ADC34_COMMON->CCR |= (0 << 13);
// DMA mode for 12-bit resolution
ADC12_COMMON->CCR |= (0b10 << 14);
ADC34_COMMON->CCR |= (0b10 << 14);
}
void DMA_init(void) {
// Enable clocks
RCC->AHBENR |= (1 << 0); // DMA1
RCC->AHBENR |= (1 << 1); // DMA2
// Transfer complete interrupt enable
DMA1_Channel1->CCR |= (1 << 1);
DMA2_Channel5->CCR |= (1 << 1);
// Memory increment mode
DMA1_Channel1->CCR |= (1 << 7);
DMA2_Channel5->CCR |= (1 << 7);
// Peripheral size
DMA1_Channel1->CCR |= (0b11 << 8);
DMA2_Channel5->CCR |= (0b11 << 8);
// Memory size
DMA1_Channel1->CCR |= (0b11 << 10);
DMA2_Channel5->CCR |= (0b11 << 10);
// Number of data to transfer
DMA1_Channel1->CNDTR = uint32_t(maxSamples);
DMA2_Channel5->CNDTR = uint32_t(maxSamples);
// Peripheral address register
DMA1_Channel1->CPAR |= (uint32_t)&ADC12_COMMON->CDR;
DMA2_Channel5->CPAR |= (uint32_t)&ADC34_COMMON->CDR;
// Memory address register
DMA1_Channel1->CMAR |= uint32_t(&dataPoints1232);
DMA2_Channel5->CMAR |= uint32_t(&dataPoints3432);
// Reset flags
DMA1->IFCR |= 0xFF;
DMA2->IFCR |= 0xFF;
}
void takeSamples(void) {
// Reset flags
DMA1->IFCR |= (0b1111111111111111111111111111111 << 0);
DMA2->IFCR |= (0b1111111111111111111111111111111 << 0);
// Number of data to transfer
DMA1_Channel1->CNDTR = uint32_t(maxSamples);
DMA2_Channel5->CNDTR = uint32_t(maxSamples);
delay(10); // does not work without this random delay
elapsedTime = micros();
// Enable DMA
DMA1_Channel1->CCR |= (1 << 0);
DMA2_Channel5->CCR |= (1 << 0);
while ((DMA1_Channel1->CNDTR > 0) || (DMA2_Channel5->CNDTR > 0))
}
elapsedTime = micros() - elapsedTime;
// Reset flags
DMA1->IFCR |= (0b1111111111111111111111111111111 << 0);
DMA2->IFCR |= (0b1111111111111111111111111111111 << 0);;
DMA1_Channel1->CCR &= ~(1 << 0);
DMA2_Channel5->CCR &= ~(1 << 0);
// ADC stop conversion
ADC1->CR |= (1 << 4);
ADC3->CR |= (1 << 4);
while ((ADC1->CR & (1 << 2)) || (ADC3->CR & (1 << 2)));
ADC12_COMMON->CCR &= ~(0b10 << 14);
ADC34_COMMON->CCR &= ~(0b10 << 14);
ADC12_COMMON->CCR |= (0b10 << 14);
ADC34_COMMON->CCR |= (0b10 << 14);
// ADC start conversion
ADC1->CR |= (1 << 2);
ADC3->CR |= (1 << 2);
}
void loop() {
takeSamples();
Serial.print("Elapsed time: ");
Serial.println(elapsedTime);
}
I would be really thankfull for any tips or hints regarding this issue!
Greetings
Benny
EDIT: I also had the same issue with the nucleo-64 with the STM32F401 chip. The STM32F4 Discovery on the other hand worked just fine. There was no issue like that with my F103 flightcontroller-board aswell.
As an example something simple with the timer trigered conversions.
void ReadChannels(int channel, size_t nsamples, uint8_t *obuff)
{
TIM1 -> CR1 = 0;
TIM1 -> CR2 = 0;
TIM1 -> PSC = PSC;
TIM1 -> ARR = ARR;
TIM1 -> EGR |= TIM_EGR_UG;
DMA1_Channel1 -> CPAR = (uint32_t)&(ADC1 -> DR);
DMA1_Channel1 -> CMAR = (uint32_t)obuff;
DMA1_Channel1 -> CNDTR = nsamples;
DMA1_Channel1 -> CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_EN;
ADC1 -> CFGR = ADC_CFGR_DMAEN | (0b10 << ADC_CFGR_RES_Pos) | (9 << ADC_CFGR_EXTSEL_Pos) | (0b01 << ADC_CFGR_EXTEN_Pos);
ADC1 -> SMPR1 = 0;
ADC1 -> SMPR2 = 0;
ADC1 -> SQR1 &= ~(ADC_SQR1_L_Msk);
ADC1 -> SQR1 &= ~(ADC_SQR1_SQ1_Msk);
ADC1 -> SQR1 |= channel << ADC_SQR1_SQ1_Pos);
ADC1 -> CR |= ADC_CR_ADSTART;
TIM1 -> CR2 |= TIM_CR2_MMS_1;
TIM1 -> CR1 |= TIM_CR1_CEN;
DMA1_Channel1 -> CCR = 0;
TIM1 -> CR1 = 0;
}