SPI not sending via DMA - spi

I'm trying to transmit data over SPI via DMA on NXP's KL05Z MCU, but I think I'm missing something in my register's setup. SPI alone works fine but when i try using DMA nothing happens. I'm pretty desperate after 2 days of reading the documentation and not finding any solution :/
uint8_t fb[10][10];
for(uint8_t y = 0; y<10;y++)
{
for(uint8_t x = 0; x<10;x++)
{
fb[y][x] = 0xAA;
}
}
SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK;
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
PORTB->PCR[8] = PORT_PCR_MUX(1);
PORTA->PCR[7] = PORT_PCR_MUX(3);
PTB->PDDR |= (1<<8);
SIM->SCGC4 |= SIM_SCGC4_SPI0_MASK;
SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_SOURCE(17);
DMAMUX0->CHCFG[0] |= DMAMUX_CHCFG_ENBL_MASK;
DMA0->DMA->SAR = (uint32_t) &fb[0][0];
DMA0->DMA->DAR = (uint32_t) &SPI0->D;
DMA0->DMA->DCR |= DMA_DCR_EINT_MASK;
DMA0->DMA->DCR |= DMA_DCR_SSIZE(1);
DMA0->DMA->DCR |= DMA_DCR_DSIZE(1);
DMA0->DMA->DCR |= DMA_DCR_ERQ_MASK;
DMA0->DMA->DCR |= DMA_DCR_SINC_MASK;
DMA0->DMA->DSR_BCR |= DMA_DSR_BCR_BCR(10);
DMA0->DMA->DCR |= DMA_DCR_START_MASK;
SPI0->C1 |= SPI_C1_MSTR_MASK;
SPI0->BR |= SPI_BR_SPPR(1);
SPI0->BR |= SPI_BR_SPR(0);
SPI0->C2 |= SPI_C2_TXDMAE_MASK;
SPI0->C1 |= SPI_C1_SPE_MASK;

Related

while (!(IFG2 & UCA0RXIFG)); Never receives data

I am currently using Code Composer studio version 10. I am working with the following code for SPI implementation. I can't get the receiver code to work atm. I would like assistance to fix the problem with receive buffer.
`
#include <msp430.h>
#include <msp430g2553.h>
/**
*/
char data_send, data_recv;
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; // stop watch dog timer
P1SEL = BIT1 | BIT2 | BIT4;
P1SEL2 = BIT1 | BIT2 | BIT4;
UCA0CTL1 |= UCSWRST ;
UCA0CTL0 |= UCMSB + UCMST + UCSYNC+ UCCKPL;
UCA0CTL1 |= UCSSEL_2;
/**
*/
while (!(IFG2 & UCA0TXIFG));
UCA0TXBUF = 0XAA;
data_send = UCA0TXBUF;
while (!(IFG2 & UCA0RXIFG));
data_recv = UCA0RXBUF;
P1OUT |= (BIT5);
return 0;
}
`
I have tried changing the values of the following code, which has not improved the problem.`
UCA0CTL1 |= UCSWRST ;
UCA0CTL0 |= UCMSB + UCMST + UCSYNC+ UCCKPL;
UCA0CTL1 |= UCSSEL_2;
`

I2C is not able to start

I am using stm8s controller and SDCC compiler. I am interfacing SD130S7 I2C based RTC with controller. I am facing a problem during communication. I think the problem is I2C itself is not started.
I am using a development board for STM8S103.
I checked on logic analyser and i see there is only one pulse on SDA pin.
I am confused how come SDA has pulse and SCL doesn't. (As SCL is clock and Clock should be present at first).
void init_i2c_master(void)
{
CLK_PCKENR1 |= 0x01; //enable i2c clocks
I2C_CR1 &= ~(0x01); //Disable the i2c before configuration starts
I2C_FREQR = 16;// Set the internal clock 16 frequency (MHz).
I2C_OARH = 0xC0; //set 7 bit addressing mode
I2C_TRISER = 16 + 1;
I2C_CCRL = (uint8_t)(16*5);
I2C_CCRH = 0;
I2C_CR1 |= 0x01; //enable i2c peripheral
I2C_CR2 |= 0x04;
I2C_CR2 &= ~0x08;
I2C_ITR |= (0x01 | 0x02);
}

STM32F3 Dual ADC with interleaved mode

I'm trying to achieve 10MSPS as documented in STM32F30x ADC modes and application under the section Dual interleaved mode.
Firstly, i tried to use single DMA. I configured the DMA1 Channel1 to read from ADC1&2 Common data register. It worked but i could only achieve a sample rate of 8.47MSPS. Beyond that limit, ADC1 starts to overrun.
(Register ADC1_2->CCR: MULT=0x07, MDMA=0x02, DELAY=0x04) Considering the DMA reading the common data register after the slave adc ends its conversion, the problem seems reasonable at high sample rates.
So i decided to use 2 DMAs. One for each ADC:
DMA1 Channel1 copies from ADC1->DR to SRAM
DMA2 Channel1 copies from ADC2->DR to SRAM
(Register ADC1_2->CCR: MULT=0x07, MDMA=0x00, DELAY=0x04)
This configuration also worked but again up to 8MSPS. Above that rate, ADC2 starts to overrun. I cannot understand why ADC2 overruns. I expected that this setup would work.
When i run ADC1 & ADC2 in independent mode with DMA configuration above, everything seems to work fine. No overruns, both ADC samples at 5.1MSPS but independently.
One question: What happens when both ADCs run in independent mode and triggered from the same source (e.g. TIM2) but ADC1 is triggered at the rising edge and ADC2 is triggered at the falling edge of the clock ? Would it work? This is the next thing i will try.
The MCU i work with is STM32F303CB.
ADC sampling times were 1.5 Cycles.
Any advice will be appreciated.
Edit: I have provided a minimal sample code that runs on STM32F3 Discovery with an 8 MHz Crystal. Program directly jumps to main()
// main.c
#include "stm32f30x.h"
#define DUALDMA
void sysinit();
void clockconfig();
void delay(int d);
void timerinit();
void adcinit();
void dmainit();
void dualdmainit();
int main(){
sysinit();
clockconfig();
timerinit();
#ifdef DUALDMA
dualdmainit();
#else
dmainit();
#endif
adcinit();
RCC->AHBENR |= RCC_AHBENR_GPIOEEN; // GPIOE enable
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; // GPIOA enable
GPIOE->MODER = 0x55555555; // GPIOE -> output
GPIOA->MODER |= 0x0000FFFF;// GPIOA -> analog
// Reset SRAM memory area
for(int i = 0;i<1024*4;i+=4){
*((uint32_t*)(0x20000800+i)) = 0;
}
// Blink LEDs
while(1){
GPIOE->ODR = 0xFFFF;
delay(1000);
GPIOE->ODR = 0x00FF;
delay(1000);
}
}
void delay(int d){
// Dummy delay
int l = d*1000;
for(int i = 0;i<l;i++);
}
void sysinit(){
//STM32F303 reset state
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= 0x00000001U;
/* Reset CFGR register */
RCC->CFGR &= 0xF87FC00CU;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= 0xFEF6FFFFU;
/* Reset HSEBYP bit */
RCC->CR &= 0xFFFBFFFFU;
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE bits */
RCC->CFGR &= 0xFF80FFFFU;
/* Reset PREDIV1[3:0] bits */
RCC->CFGR2 &= 0xFFFFFFF0U;
/* Reset USARTSW[1:0], I2CSW and TIMs bits */
RCC->CFGR3 &= 0xFF00FCCCU;
/* Disable all interrupts */
RCC->CIR = 0x00000000U;
SCB->VTOR = 0x08000000; /* Vector Table Relocation in Internal FLASH */
}
void adcinit(){
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable ADC clock
RCC->CFGR2 |= RCC_CFGR2_ADCPRE12_4;// ADC clock prescaler = 1
ADC1->CFGR |= ADC_CFGR_EXTEN_0; // Trigger on rising edge
ADC1->CFGR |= ADC_CFGR_EXTSEL_3 | ADC_CFGR_EXTSEL_1; // TIM1 TRGO2
ADC1->SQR1 |= ADC_SQR1_SQ1_0 ; // ch 1
ADC1->CFGR |= ADC_CFGR_OVRMOD; // Stop on overrun
ADC1->CFGR |= ADC_CFGR_DMAEN; // DMA enable
ADC1->CR &= ~(ADC_CR_ADVREGEN_1 | ADC_CR_ADVREGEN_0); // Enable VREG
ADC1->CR |= ADC_CR_ADVREGEN_0;
ADC1->CR |= ADC_CR_ADEN;
while( (ADC1->ISR & ADC_ISR_ADRD) == 0 );
ADC2->SQR1 |= ADC_SQR1_SQ1_0 ; // ch 1
ADC2->CFGR |= ADC_CFGR_DMAEN;
ADC2->CR &= ~(ADC_CR_ADVREGEN_1 | ADC_CR_ADVREGEN_0);
ADC2->CR |= ADC_CR_ADVREGEN_0;
ADC2->CR |= ADC_CR_ADEN;
while( (ADC1->ISR & ADC_ISR_ADRD) == 0 );
ADC1_2->CCR |= ADC12_CCR_DELAY_2 ; // Delay = 4, 5 Cycles
#ifndef DUALDMA
ADC1_2->CCR |= ADC12_CCR_MDMA_1; // If single DMA is selected, configure MDMA bits for 12 bits
#endif
ADC1_2->CCR |= ADC12_CCR_MULTI_2 | ADC12_CCR_MULTI_1 | ADC12_CCR_MULTI_0; // Interleaved mode
}
void dmainit(){
// DMA config for Single DMA, 32 bits
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CPAR = (uint32_t)&ADC1_2->CDR;
DMA1_Channel1->CMAR = 0x20000800;
DMA1_Channel1->CNDTR = 1024;
DMA1_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC | DMA_CCR_MSIZE_1 | DMA_CCR_PSIZE_1;
//DMA1_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC ;
}
void dualdmainit(){
// DMA config for DUAL DMA, 16bits
RCC->AHBENR |= RCC_AHBENR_DMA1EN; // DMA1 Enable
RCC->AHBENR |= RCC_AHBENR_DMA2EN; // DMA2 Enable
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
DMA1_Channel1->CMAR = 0x20000800;
DMA1_Channel1->CNDTR = 1024;
DMA1_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0;
DMA2_Channel1->CPAR = (uint32_t)&ADC2->DR;
DMA2_Channel1->CMAR = 0x20000800+1024*2;
DMA2_Channel1->CNDTR = 1024;
DMA2_Channel1->CCR = DMA_CCR_EN | DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0;
}
void timerinit(){
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // Enable TIM1
TIM1->CR2 |= TIM_CR2_MMS2_1; // Update event selected as TRGO2
TIM1->PSC = 0;
TIM1->ARR = 0x0d; // 5 MHz (72 MHz / 14 )
TIM1->CR1 |= TIM_CR1_CEN;
}
void clockconfig(){
// External oscillator (HSE): 8MHz
RCC->CR |= RCC_CR_HSEON; // Enable HSE
while( (RCC->CR & RCC_CR_HSERDY) == 0 );
RCC->CFGR |= RCC_CFGR_PLLMULL9; // PLL MUL = x9
RCC->CFGR |= RCC_CFGR_PPRE1_DIV2; // APB1 Prescaler = 2
RCC->CFGR |= RCC_CFGR_PLLSRC; // PLL source = HSE
FLASH->ACR |= FLASH_ACR_LATENCY_1; // Two wait states
RCC->CR |= RCC_CR_PLLON; // Enable and wait PLL
while( (RCC->CR & RCC_CR_PLLRDY) == 0 );
RCC->CFGR |= RCC_CFGR_SW_PLL; // Select PLL as system clock
}
Scatter file:
LR_IROM1 0x08000000 0x00020000 { ; load region size_region
ER_IROM1 0x08000000 0x00020000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM2 0x10000000 0x00000200 { ; RW data
.ANY (+RW +ZI)
}
}
You cant do it this way. You need to use only one DMA channel and both samples are transmitted in one 32 bit DMA transaction.
In 6 bits mode I have archived more than 18MSPS
I do not know how to program it using HAL as I personally do only the bare register approach
There is a hardware problem as well (read the errata) and sometimes in >8bit modes the transfer does not work properly.
For dual DMA you need to:
Prevent any core accesses to the SRAM memory by placing the stack and the variables (except the ADC buffers) in the CCM RAM or suspending any core activity by entering the sleep mode.

Attiny 84 Communicating with RTC Through SPI Troubles

I am currently trying to use an ATtiny84 to communicate with an RTC (DS1305) through SPI to make an buzzer vibrate every variable amount of time. I've been trying to set alarm0 on the DS1305. However, the 84 does not "technically" have SPI. It has USI which can be programmed to be like SPI. I was wondering if any of you could review my code/ board connections and let me know if you see any problems. The current problem is that I cannot get any communication going through SPI and I am having trouble finding what the issue could be.
Current board connections:
ATtiny84 | DS1305
MOSI ------ DI
MISO ------ DO
USCLK ---- CLK
Datasheets:
Attiny84
DS1305
/*
* Atmel_Jolt_Code.c
*
* Created: 11/28/2018 10:44:30 PM
* Author : Nick Hulsey
*/
#include <avr/io.h>
#define F_CPU 16000000UL
#include <avr/interrupt.h>
#include <util/delay.h>
//variables for SPI
#define SPI_DDR_PORT DDRA
#define CE_PIN DDA3 //I ADDED *****
#define DO_DD_PIN DDA5 // SHOULD WE
#define DI_DD_PIN DDA6 // THEM FLIP
#define USCK_DD_PIN DDA4
#define SPI_MODE0 0x00
#define SPI_MODE1 0x04
#define MOTOR_PIN DDA7 //I ADDED *****
void SPI_begin();
void setDataMode(uint8_t spiDataMode);
uint8_t transfer(uint8_t spiData);
void flipLatch(uint8_t on);
int main(void)
{
SPI_begin();
setDataMode(SPI_MODE1);
DDRA |= (1 << MOTOR_PIN);
//**startup**
uint8_t status_register = 0x10;
uint8_t control_register = 0x8F;
uint8_t control_byte = 0x05;
uint8_t alarm_registers[] = {0x8A, 0x89, 0x88, 0x87};
//set control
flipLatch(1);
transfer(control_register);
transfer(0);
flipLatch(0);
flipLatch(1);
transfer(control_register);
transfer(control_byte);
flipLatch(0);
//set alarm:
for (int i = 0; i < 4; i++){
flipLatch(1);
transfer(alarm_registers[i]);
transfer(0x80); //0b10000000
flipLatch(0);
}
//THIS MIGHT NEED WORK
//GIMSK |= (1 << PCIE1);//set external interrupt (A1)
PCMSK0 |= (1 << PCINT1);
sei();
while (1) //our main loop
{
//reading the flag from the status register
uint8_t status = transfer(status_register);
if(status == 0x01){//if alarm 0 has been flagged
PORTA ^= (1 << MOTOR_PIN);
_delay_ms(100);
}
}
}
//if A1 has changed state at all this function will fire
ISR(PCINT1_vect){
PORTA ^= (1 << MOTOR_PIN);//invert motor power
_delay_ms(100);
}
void SPI_begin(){
USICR &= ~((1 << USISIE) | (1 << USIOIE) | (1 << USIWM0));//Turn off these bits
USICR |= (1 << USIWM0) | (1 << USICS1) | (1 << USICLK);//Turn on these bits
//REVIEW THIS PAGE 128
//external,positive edge software clock
//What does this mean
SPI_DDR_PORT |= 1 << USCK_DD_PIN; // set the USCK pin as output
SPI_DDR_PORT |= 1 << DO_DD_PIN; // set the DO pin as output
SPI_DDR_PORT |= 1 << CE_PIN;// ******** I ADDED
SPI_DDR_PORT &= ~(1 << DI_DD_PIN); // set the DI pin as input
}
void setDataMode(uint8_t spiDataMode)
{
if (spiDataMode == SPI_MODE1)
USICR |= (1 << USICS0);
else
USICR &= (1 << USICS0);
}
//returns values returned from the IC
uint8_t transfer(uint8_t spiData)
{
USIDR = spiData;
USISR = (1 << USIOIF); // clear counter and counter overflow interrupt flag
//ATOMIC_BLOCK(ATOMIC_RESTORESTATE) // ensure a consistent clock period
//{
while ( !(USISR & (1 << USIOIF)) ) USICR |= (1 << USITC);
//}
return USIDR;
}
void flipLatch(uint8_t on){
if (on == 1)
PORTA |= (1 << CE_PIN);
else
PORTA &= ~(1 << CE_PIN);
}

atmega 328p interrupt and timer setup [C/C++]

I am trying to set up one interrupt and one counter/timer. The interrupt is external, reading low logic from pin. Timer should increment every 100 us and add up to count variable.
I've set up the interrupt, which is working fine however, after setting up a timer, neither interrupt nor timer works. The code is such:
volatile boolean allowCount = false, timerFlag = false;
volatile unsigned int counter;
boolean pulseLow = false;
void setup(){
Serial.begin(9600);
// initialize external pin interrupt.
PCICR = 0b00000010; // 1. PCIE1: Pin Change Interrupt Enable 1
EICRA |= bit (ISC10); // set wanted flags (low logic level causes interrupt)
PCMSK1 = 0b00010000; // Enable Pin Change Interrupt for A4
// TODO Interrupt settings not working together
// initialize Timer1
cli(); // disable global interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
// set compare match register to desired timer count:
OCR1A = 0x18;
// turn on CTC mode:
TCCR1B |= (1 << WGM12);
// Set CS10 and CS12 bits for 64 prescaler:
TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS11);
// enable timer compare interrupt:
TIMSK1 |= (1 << OCIE1A);
}
void loop(){
if (allowCount == true)
{ timer100_uS();
if (counter > 50 && pulseLow == false){
DDRC |= (1 << DDC3 ); // sets bit DDC3 to 1 within register DDRC
//set pin 3(A3) ouput as sourcing Vcc(HIGH)
PORTC |= (1 << PORTC3);
timerReset();
pulseLow = true;
}
if (pulseLow == true){
timer100_uS();
if (counter >= 500){
//set pin3 of port C to LOW (A3);
PORTC &= ~(1 << PORTC3);
pulseLow = false
timerReset();
}
}
// external pin interrupt
ISR(PCINT1_vect){
if (allowCount == false)
allowCount = true;
}
// timer/counter interrupt
ISR (TIMER1_COMPA_vect)
{
if (timerFlag == true){
counter++;
}
}
void timer_100uS(void){
timerFlag = true;
cli();
}
void timerReset(void){
sei();
timerFlag = false;
counter = 0;
}
Value of OCR0A is calculated to be 24 (0x18) with prescaler 64 and 16 MHz processor based on this formula:
OCRn = [ (clock_speed / Prescaler_value) * Desired_time_in_Seconds ] - 1
How to set up different interrupts so that they don't overlap eachother ?
Or better yet, is it possible to set up timer so that it does not use interrupt ?
Thanks for reading !
As I can see, you are using ATMega328 with Arduino libraries. Your problem is that Arduino library internally uses Timer 1 for its internal purposes. Therefore if you add your own interrupt handler for Timer 1, you override Arduino's interrupt handler for Timer 1 which breaks the library.
If you want to stay with Arduino library, use the library also to control the timer: Arduino Timer1
Thank you for answers #old_timer, #klasyc.
Quite late, but I solved it by using timer0 instead of timer1 with following settings in setup:
// initialize external pin interrupt.
PCICR = 0b00000010; // 1. PCIE1: Pin Change Interrupt Enable 1
EICRA |= bit (ISC10); // set wanted flags (falling edge causes interrupt)
PCMSK1 = 0b00001000; // Enable Pin Change Interrupt for A3
TCCR0B = 0;
TCCR0A = 0;
//set CTC mode
TCCR0A = ( 1 << WGM01 );
// set OCR0A value for 1 us counter (OCRxn = (freq/prescaler)*desired_value)-1
OCR0A = 15;
// set compare match counter
TIMSK0 |= (1 << OCIE0A);
//set prescaler
TCCR0B |= ( 1 << CS00);
and outside the loop:
ISR(TIMER0_COMPA_vect){
counter++;
}