Trigger SPI communication using a timer - timer

I'm trying to trigger a SPI communication using a timer on the NXP LPC1788 microcontroller. In the features of the DMA user manual it's written that the controller can use a timer for triggering a DMA burst. But I can't find a hint where the trigger source is configured in the DMA controller.
I plan to send a high frequent SPI command and read the result SPI with the same frequency using the DMA Controller. The transfer should be triggered by a timer. Is this possible?
Of cause I can implement the transfer in a timer ISR. But the controller is already busy doing other more important things.
Edit:
Today I had time to retry this again. I Use timer 3 match 0 to count with 1 kHz. Then I configured DMA stream 3 with source peripheral type TIM3M0 and destination connection type SSP0 TX. The timer triggers the DMA transfer once but then the channel is disabled.
So the configuration seams to be correct as the data gets transferred once as expected. So I tried to configure circular mode for DMA. I found the linked list configuration within the DMA controller what seams perfect. I added one element link to itself to close the loop. Now If I run this example the timer triggers the DMA channel again and the communication starts in an endless loop running as fast as possible. That's also not what I wanted to archive. Why is it not waiting for the trigger condition of the source peripheral. At the moment I think this is not possible with this microcontroller.
I add my current register configuration here:
Timer configuration
DMA source peripheral selection
DMA stream 3 configuration
Edit 2:
I also think that there is a small chance that this is possible. You have to use 3 channels.
Channel 4 is a memory to memory transfer. It gets triggered by timer 3 match 0. The task is to reconfigure and enable channel 3 and channel 5.
Channel 3 is used for Memory to SPI Peripheral transfer
Channel 5 is also a memory to memory transfer used to reconfigure Channel 4 finally. This one closes the loop
I added the code I'm testing at the moment. The chain runs once as expected. But reenabling the chain is not working yet. I added three test elements to the chains to see if the get executed. Do you see any obvious error?
The problem is you have to reconfigure the entire DMA channel with all registers after channel transfer termination.
GPDMA_LLI_Type linkedListEntry[15];
uint32_t specialControlSPI = 0x0;
uint32_t specialControlEnable = 0x0;
uint32_t specialConfigSPI = 0x0;
uint32_t specialConfigEnable = 0x0;
uint32_t specialConfigReenab = 0x0;
uint32_t specialCotrolReenab = 0x0;
uint32_t linkedListEnab = 0x0;
uint32_t linkedListReenab = 0x0;
uint32_t myTest = 0x0;
uint32_t myTest2 = 0x0;
uint32_t srcDataRegisterSPI = 0x0;
uint32_t srcDataRegisterEnab= 0x0;
uint32_t srcDataRegisterReenab = 0x0;
uint32_t destDataRegisterEnab= 0x0;
uint32_t destDataRegisterReenab = 0x0;
const uint32_t pattern1 = 0xAABBCCDD;
const uint32_t pattern2 = 0xEEFF0088;
#define MEMORY_TRANSFER_BURST (GPDMA_BSIZE_1)
#define MEMORY_TRANSFER_WIDTH (GPDMA_WIDTH_WORD)
void configureDMA_ForSPI_ADC_Tx(DMA dmaTx, void* data, uint32_t size)
{
//Disable all required channels
GPDMA_ChannelCmd(3, DISABLE);
GPDMA_ChannelCmd(4, DISABLE);
GPDMA_ChannelCmd(5, DISABLE);
//Form spcecial control for "enable" channel
uint32_t specialControl = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
uint32_t j = 0;
//Configure "enable" channel to be triggered by timer 3 match 0 resulting in a memory transfer
GPDMA_Channel_CFG_Type conf;
conf.ChannelNum = 4;
conf.DstConn = 0;
conf.SrcConn = GPDMA_CONN_MAT3_0;
conf.TransferType = GPDMA_TRANSFER_M2M_CTRL_DMA;
conf.SrcMemAddr = (uint32_t)&specialControlSPI;
conf.TransferSize = 4;
conf.DstMemAddr = (uint32_t)&LPC_GPDMACH3->CControl;
conf.DMALLI = (uint32_t)&linkedListEntry[j],
GPDMA_Setup(&conf, &specialControl);
//Prepare linked list to enable "enable" channel again
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH3->CSrcAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterSPI;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH3->CConfig; ///Enable SPI channel
linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigSPI;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CControl;
linkedListEntry[j].SrcAddr = (uint32_t)&specialCotrolReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CLLI;
linkedListEntry[j].SrcAddr = (uint32_t)&linkedListReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CDestAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&destDataRegisterReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CSrcAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CConfig; ///Enable "Reenable" channel
linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH7->CControl;
linkedListEntry[j].SrcAddr = (uint32_t)&pattern1;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&myTest;
linkedListEntry[j].SrcAddr = (uint32_t)&pattern1;
linkedListEntry[j].NextLLI = 0;
j++;
//------------------------------------------------------------------------------------------------------------------
//Form special control for "SPI" channel
specialControl = GPDMA_DMACCxControl_TransferSize(size) \
| GPDMA_DMACCxControl_SBSize((uint32_t)GPDMA_BSIZE_1)
| GPDMA_DMACCxControl_DBSize((uint32_t)GPDMA_BSIZE_1)
| GPDMA_DMACCxControl_SWidth((uint32_t)GPDMA_WIDTH_HALFWORD)
| GPDMA_DMACCxControl_DWidth((uint32_t)GPDMA_WIDTH_HALFWORD)
| GPDMA_DMACCxControl_SI;
//Configure "SPI" channel to be triggered by software resulting in a peripheral transfer and a memory transfer in linked list
conf.ChannelNum = 3;
conf.DMALLI = 0,
conf.DstConn = GPDMA_CONN_SSP0_Tx;
conf.SrcConn = 0;
conf.TransferType = GPDMA_TRANSFER_M2P_CTRL_DMA;
conf.SrcMemAddr = (uint32_t)data;
conf.TransferSize = size;
conf.DstMemAddr = 0;
GPDMA_Setup(&conf, &specialControl);
//------------------------------------------------------------------------------------------------------------------
//Form special control for "reenab" channel
specialControl = GPDMA_DMACCxControl_TransferSize(size)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
//Configure "SPI" channel to be triggered by software resulting in a peripheral transfer and a memory transfer in linked list
conf.ChannelNum = 5;
conf.DstConn = 0;
conf.SrcConn = 0;
conf.TransferType = GPDMA_TRANSFER_M2M_CTRL_DMA;
conf.TransferSize = 4;
conf.SrcMemAddr = (uint32_t)&specialControlEnable;
conf.DstMemAddr = (uint32_t)&LPC_GPDMACH4->CControl;
conf.DMALLI = (uint32_t)&linkedListEntry[j],
GPDMA_Setup(&conf, &specialControl);
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CLLI;
linkedListEntry[j].SrcAddr = (uint32_t)&linkedListEnab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CDestAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&destDataRegisterEnab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CSrcAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterEnab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
//Prepare linked list to enable "enable" channel again
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CConfig;
linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigEnable; ///Enable trigger channel again
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&myTest2;
linkedListEntry[j].SrcAddr = (uint32_t)&pattern2;
linkedListEntry[j].NextLLI = 0;
j++;
//Store the configuration registers for DMA operation
specialControlSPI = LPC_GPDMACH3->CControl | GPDMA_DMACCxControl_TransferSize(size);
specialControlEnable = LPC_GPDMACH4->CControl | GPDMA_DMACCxControl_TransferSize(4);
specialCotrolReenab = LPC_GPDMACH5->CControl | GPDMA_DMACCxControl_TransferSize(4);
srcDataRegisterSPI = LPC_GPDMACH3->CSrcAddr;
srcDataRegisterEnab = LPC_GPDMACH4->CSrcAddr;
srcDataRegisterReenab = LPC_GPDMACH5->CSrcAddr;
destDataRegisterEnab = LPC_GPDMACH4->CDestAddr;
destDataRegisterReenab = LPC_GPDMACH5->CDestAddr;
specialConfigSPI = (0x1) | LPC_GPDMACH3->CConfig;
specialConfigEnable = (0x1) | LPC_GPDMACH4->CConfig;
specialConfigReenab = (0x1) | LPC_GPDMACH5->CConfig;
linkedListReenab = LPC_GPDMACH5->CLLI;
linkedListEnab = LPC_GPDMACH4->CLLI;
//Enable the channel "enable" channel. Hopfully will be triggered by timer match soon. This should enable SPI transfer
GPDMA_ChannelCmd(4, ENABLE);
}

Related

Configuring ATSAM3x8e port to output

I am having an issue configuring my SAM3x8e port to output, when I check the pin with a multimeter I get 1.5V so the pin 0 of Port A just isn't turning on. I believe I configured the port pins to correctly out as outputs but I do not know, I don't have a debugger on me to look at what's happening internally.
#include "sam.h"
uint32_t right_tick = 0;
uint32_t left_tick = 0;
uint32_t LED_status = 1;
void InitializeSystemTimer(void)
{
const uint32_t tickcount = 1000000;
// set value countdown restarts to
SysTick->LOAD = tickcount;
// set interrupt priority
NVIC_SetPriority(SysTick_IRQn, 3);
// restart timer
SysTick->VAL = 0;
// set system tick counter ClockSource/8, creates system tick exception when hits 0, enable system tick count,
SysTick->CTRL = SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;
}
void InitializeIOPorts(void)
{
// enable Peripheral Clock on Port A
PMC->PMC_PCER0 = ID_PIOA;
// configure output pins
// claim Port A control of pin 0, 1, 2
PIOA->PIO_PER = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// enable Port A output on pins
PIOA->PIO_WPMR = PIO_WPMR_WPKEY_Msk;
// set Port A pin 0, 1, 2 to output
PIOA->PIO_PER = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// set Port A pin 0, 1, 2 to be accessed directly by setting Output Write Enable Register
PIOA->PIO_OWER = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// set Port A pin 0, 1, 2 to high
PIOA->PIO_ODSR = PIO_PER_P0|PIO_PER_P1|PIO_PER_P2;
// configure input pins
// claim Port A control of pin 3, 4
PIOA->PIO_PER = PIO_PER_P3|PIO_PER_P4;
// set pull up resistors on pin 3, 4
PIOA->PIO_PUER = PIO_PER_P3|PIO_PER_P4;
// set interrupt on pin 3, 4
PIOA->PIO_IER = PIO_PER_P3|PIO_PER_P4;
// enable input change interrupt on Pin 3, 4 by setting mask
PIOA->PIO_IMR = PIO_PER_P3|PIO_PER_P4;
// set priority and enable interrupt for port A
NVIC_SetPriority(PIOA_IRQn, 3);
NVIC_EnableIRQ(PIOA_IRQn);
}
void InitializeUart(void)
{
PMC->PMC_PCER0 = ID_UART;
// baud rate is 84Mhz/(16*45)
UART->UART_BRGR = uint32_t(45);
UART->UART_CR = UART_CR_TXEN|UART_CR_RXEN;
NVIC_SetPriority(UART_IRQn,2);
NVIC_EnableIRQ(UART_IRQn);
}
void SysTick_Handler(void)
{
if (LED_status == 0)
{
PIOA->PIO_SODR = PIO_PER_P0;
LED_status = 1;
}
else
{
PIOA->PIO_CODR = PIO_PER_P0;
LED_status = 0;
}
}
void PIOA_Handler(void)
{
uint32_t PORTA_interrupt_status = 0;
PORTA_interrupt_status = PIOA->PIO_ISR;
if ((PORTA_interrupt_status&PIO_PER_P3) == 1)
{
left_tick = left_tick+1;
}
if ((PORTA_interrupt_status&PIO_PER_P4) == 1)
{
right_tick = right_tick + 1;
}
}
void UART_Handler(void)
{
}
int main(void)
{
/* Initialize the SAM system */
SystemInit();
InitializeSystemTimer();
InitializeIOPorts();
/* Replace with your application code */
while (1)
{
}
}
You should double check an example given in the Atmel SAM3X8E Datasheet in the section 31.6 I/O Lines Programming Example.
Have a look at example provided:
Four output signals on I/O lines 4 to 7 (to drive LEDs for example),
driven high and low, no pull-up resistor
and the following configuration:
Register Value to be Written
PIO_PER 0x0000FFFF
PIO_PDR 0xFFFF0000
PIO_OER 0x000000FF
PIO_ODR 0xFFFFFF00
PIO_IFER 0x00000F00
PIO_IFDR 0xFFFFF0FF
PIO_SODR 0x00000000
PIO_CODR 0x0FFFFFFF
PIO_IER 0x0F000F00
PIO_IDR 0xF0FFF0FF
PIO_MDER 0x0000000F
PIO_MDDR 0xFFFFFFF0
PIO_PUDR 0xF0F000F0
PIO_PUER 0x0F0FFF0F
PIO_ABSR 0x00F00000
PIO_OWER 0x0000000F
PIO_OWDR 0x0FFFFFF0
We need the second character from the end (as far as pins 4 to 7 are used in this example) to determine wheather the register should be programmed or not. For instance, "PIO_PER 0x0000FFFF" means the register should be programmed. And, in contrast, "PIO_PDR 0xFFFF0000" means the register should be left untouched.
Thus, the following configuration could is obtained:
PIOA->PIO_PER = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_OER = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_IFDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_CODR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_IDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_MDDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_PUDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
PIOA->PIO_OWDR = PIO_PER_P0 | PIO_PER_P1 | PIO_PER_P2;
I have no SAM3X8E device to check this configuration, but the above considerations may help to find a solution to your problem.

How to read data from MPU6050 using SAM4S

I'm trying to read information from an MPU6050 sensor using the SAM4S-EK2 dev board, with an ATSAM4SD32C microcontroler, showing the data in the on-board LCD display. However, when I try to read the data, the received value that shows up in the LCD is always the same.
What am I doing wrong?
I'm using Atmel Studio 7 with ASF version 3.32.0
Here is my current code:
#include <asf.h>
#define TWI_CLK 200000
#define ADDRESS 0x68
#define READ 0x3b
#define ILI93XX_LCD_CS 1
twi_options_t opt;
struct ili93xx_opt_t g_ili93xx_display_opt;
void configure_lcd()
{
/** Enable peripheral clock */
pmc_enable_periph_clk(ID_SMC);
/** Configure SMC interface for Lcd */
smc_set_setup_timing(SMC, ILI93XX_LCD_CS, SMC_SETUP_NWE_SETUP(2)
| SMC_SETUP_NCS_WR_SETUP(2)
| SMC_SETUP_NRD_SETUP(2)
| SMC_SETUP_NCS_RD_SETUP(2));
smc_set_pulse_timing(SMC, ILI93XX_LCD_CS, SMC_PULSE_NWE_PULSE(4)
| SMC_PULSE_NCS_WR_PULSE(4)
| SMC_PULSE_NRD_PULSE(10)
| SMC_PULSE_NCS_RD_PULSE(10));
smc_set_cycle_timing(SMC, ILI93XX_LCD_CS, SMC_CYCLE_NWE_CYCLE(10)
| SMC_CYCLE_NRD_CYCLE(22));
smc_set_mode(SMC, ILI93XX_LCD_CS, SMC_MODE_READ_MODE
| SMC_MODE_WRITE_MODE);
/** Initialize display parameter */
g_ili93xx_display_opt.ul_width = ILI93XX_LCD_WIDTH;
g_ili93xx_display_opt.ul_height = ILI93XX_LCD_HEIGHT;
g_ili93xx_display_opt.foreground_color = COLOR_BLACK;
g_ili93xx_display_opt.background_color = COLOR_WHITE;
/** Switch off backlight */
aat31xx_disable_backlight();
/** Initialize LCD */
ili93xx_init(&g_ili93xx_display_opt);
/** Set backlight level */
aat31xx_set_backlight(AAT31XX_AVG_BACKLIGHT_LEVEL);
ili93xx_set_foreground_color(COLOR_WHITE);
ili93xx_draw_filled_rectangle(0, 0, ILI93XX_LCD_WIDTH,
ILI93XX_LCD_HEIGHT);
/** Turn on LCD */
ili93xx_display_on();
ili93xx_set_cursor_position(0, 0);
}
int main (void)
{
sysclk_init();
board_init();
configure_lcd();
pio_configure(PIOB, PIO_PERIPH_B, (PIO_PB5A_TWCK1 | PIO_PB4A_TWD1), PIO_OPENDRAIN);
pmc_enable_periph_clk(ID_TWI1);
opt.master_clk = sysclk_get_peripheral_hz();
opt.speed = TWI_CLK;
twi_enable_master_mode(TWI1);
twi_master_init(TWI1, &opt);
twi_packet_t packet;
uint8_t answer[20];
answer[0]=0x00;
//pacote.addr[0] = 0x6b;
//pacote.addr_length = 1;
//pacote.buffer = &resposta;
//pacote.chip = ENDERECO_SENSOR;
//pacote.length = 1;
//
//if(twi_master_write(TWI1, &pacote) == TWI_SUCCESS)
//{
//ili93xx_set_foreground_color(COLOR_WHITE);
//ili93xx_draw_filled_rectangle(0, 0, 200, 200);
//ili93xx_set_foreground_color(COLOR_BLACK);
//ili93xx_draw_string(0, 0, "Enviou");
//}
while(1)
{
packet.addr[0] = READ;
packet.addr_length = 1;
packet.buffer = &answer;
packet.chip = ADDRESS;
packet.length = 14;
twi_master_read(TWI1, &packet);
char a[20];
int16_t b;
b = (answer[2] << 8 | answer[3]);
sprintf(a,"%i",b);
ili93xx_set_foreground_color(COLOR_WHITE);
ili93xx_draw_filled_rectangle(95, 175, 240, 200);
ili93xx_set_foreground_color(COLOR_BLACK);
ili93xx_draw_string(100, 180, a);
delay_ms(100);
}
}

Trying to make buzzer work for TI CC2650 SensorTag

#include <ti/sysbios/family/arm/cc26xx/Power.h>
#include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
#include <driverLib/timer.h>
Task_Struct taskStruct;
void taskFxn(UArg a0, UArg a1);
PIN_init(BoardGpioInitTable);
Task_Params params;
Task_Params_init(&params);
params.priority = TASK_PRI;
params.stackSize = TASK_STACK_SIZE;
params.stack = taskStack;
Task_construct(&taskStruct, taskFxn, &params, NULL);
BIOS_start();
bool timerEnabled = 0;
PIN_Config pwmExamplePins[] = {
Board_LED1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_LED2 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
Board_KEY_SELECT | PIN_INPUT_EN | PIN_HYSTERESIS | PIN_HYSTERESIS | PIN_PULLUP | PIN_IRQ_NEGEDGE,
PIN_TERMINATE };
PIN_State pinState;
PIN_Handle pinHandle;
static void timerInitialize() {
TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);
TimerLoadSet(GPT0_BASE, TIMER_A, TIMER_LOADSET);
TimerMatchSet(GPT0_BASE, TIMER_A, TIMER_MATCH);
//Stall timer when halting debugger
//TimerStallControl(GPT0_BASE, TIMER_A, true)
}
static void pinCallBack(PIN_Handle handle, PIN_Id pinId) {
if( timerEnabled) {
timerEnabled = 0;
// Allow standby in TI RTOS and stop timer
Power_releaseConstraint(Power_SB_DISALLOW);
TimerDisable(GPT0_BASE, TIMER_A);
}
else {
timerEnabled = 1;
// Disallow standby in TI RTOS to allow timer to run
Power_setConstraint(Power_SB_DISALLOW);
TimerEnable(GPT0_BASE, TIMER_A);
}
void taskFxn(UArg a0, UArg a1) {
// Register client for pins in pwmExamplePins array
pinHandle = PIN_open(&pinState, pwmExamplePins);
// Route LED1 pin on SmartRF06EB to IO event port 0 (0 = Timer0A, 1 = Timer0B, 2 = Timer1A..)
PINCC26XX_setMux(pinHandle, PIN_ID(Board_LED1), IOC_PORT_MCU_PORT_EVENT0);
PIN_registerIntCb(pinHandle, pinCallBack);
// Turn on PERIPH power domain and clock for GPT0
Power_setDependency(PERIPH_GPT0);
timerInitialize();
// 100ms
uint32_t sleepTicks = 100 * 1000/Clock_tickPeriod;
bool ledValue = 0;
while(1) {
// Let task sleep, chip will go into IDLE or STANDBY mode depending on whether timer is enabled
Task_sleep(sleepTicks);
PIN_setOutputValue(pinHandle, PIN_ID(Board_LED2), ledValue);
// Invert LED value
ledValue = (ledValue ? 0 : 1);
}
Trying to make buzzer work for the CC2650STK SensorTag Texas Instruments device from an example, but it keeps giving the same error and not able to continue further.
fatal error #1965: cannot open source file
"ti/sysbios/family/arm/cc26xx/Power.h"
Is there some file missing from the device itself or should something be downloaded as an extra to continue?
Thank you for your help.

data link layer programming in c

I'm totally newbie about this thing and I want to know where to start..
I have a manual that specifies data link layer that includes command and response frames to access a device connected in /dev/ttyUSB0.
Example of the given command frame is setting the baud rate
Head = 0x0A
Address = NULL/blank
Length = 0x03
Command = 0x20
Parameter = 0x00
Check = cc
Where parameter 0x00 is equal to baud rate 9600bps.
My question is how do I use this in programming? can I use it on C language?
My OS platform is ubuntu 12.04.
Any link or idea would be a great help.
UPDATE
This is the command I used in read()
unsigned char rx_buffer[1024];
size_t RX_buffer_len;
ssize_t bytes_read;
int fd;
RX_buffer_len = sizeof(rx_buffer);
bytes_read = read (serial, rx_buffer, RX_buffer_len);
You could start defining the your packet message structure
// Enable 1 byte alignment
#pragma pack(1)
typedef struct
{
uint8_t Head;
uint8_t Address;
uint8_t Length;
uint8_t Command;
uint8_t Parameter;
uint8_t Check;
}typ_packet;
// Restore the original alignment
#pragma pack()
Then you can access and configure ttyUSB0. A simple example:
struct termios2 t;
int serial, baud;
// Open the uart low level device driver and set up all params
serial_fd = open("/dev/ttyUSB0", O_NOCTTY | O_NDELAY);
if (serial != -1)
{
baud = 9600;
if (ioctl(serial, TCGETS2, &t))
{
// Fails to read tty pars
exit(1);
}
t.c_cflag &= ~CBAUD;
t.c_cflag |= BOTHER;
t.c_cflag |= CSTOPB;
t.c_ospeed = baud;
// Noncanonical mode, disable signals, extended
// input processing, and echoing
t.c_lflag &= ~(ICANON | ISIG | IEXTEN | ECHO);
// Disable special handling of CR, NL, and BREAK.
// No 8th-bit stripping or parity error handling.
// Disable START/STOP output flow control.
t.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | INLCR |
INPCK | ISTRIP | IXON | PARMRK);
// Disable all output processing
t.c_oflag &= ~OPOST;
if (ioctl(serial, TCSETS2, &t))
{
// Failed to set serial parameters
exit(1);
}
}
else
{
// Failed to open ttyUSB0
exit(1);
}
Then you can simply read from serial line by
res = read (serial_fd, rx_buffer, RX_buffer_len);
And write using
typ_packet packet;
packet.Head = 0x0A;
packet.Address = 0x00;
packet.Length = 0x03;
packet.Command = 0x20;
packet.Parameter = 0x00;
packet.Check = 0xCC;
write(serial_fd, &packet, 6);

Cannot read from/write to external SRAM using FMC on STM32F429I-Disco board

I am currently using a STM32F429I Disco board with full FMC (FSMC on F407) pins to try to connect to IS62WV51216BLL SRAM module from Waveshare without much success.
The main SRAM test/initialization code has been given down below.
Apologies for the length of the post. I have tried checking and comparing with all the available codes in the internet, but somehow, it just does not initialize [test value is not returned]
The code was built and debugged in IAR workbench
SRAM_ADR
#define SRAM_ADR ((uint32_t)0x60000000)
#define SRAM_END SRAM_ADR + ((uint32_t)0x7FFFF) // not required for test
SRAM initialization, read, and write Code
//--------------------------------------------------------------
// Includes
//--------------------------------------------------------------
#include "stm32_ub_sram.h"
//--------------------------------------------------------------
// Internal Function
//--------------------------------------------------------------
void P_SRAM_InitIO(void);
void P_SRAM_InitFMC(void);
//--------------------------------------------------------------
// Initialize External SRAM
// Return_value :
// -> ERROR , when SRAM does not configured properly
// -> SUCCESS , when SRAM configured successfully
//--------------------------------------------------------------
ErrorStatus UB_SRAM_Init(void)
{
ErrorStatus ret_value = ERROR;
uint16_t oldvalue, isvalue;
// IO-Lines initialization
P_SRAM_InitIO();
// FMC initialization
P_SRAM_InitFMC();
//-----------------------------------------
// Check the SRAM live or dead
// Depends on testing the Adress 0x00
//-----------------------------------------
oldvalue = UB_SRAM_Read(0x00);
UB_SRAM_Write(0x00, 0x5A3C);
isvalue = UB_SRAM_Read(0x00);
UB_SRAM_Write(0x00, oldvalue);
if(isvalue == 0x5A3C)
ret_value = SUCCESS; // RAM verification
return(ret_value);
}
//--------------------------------------------------------------
// Internal Function
// Initialize all IO-Pins for the SRAM
//--------------------------------------------------------------
void P_SRAM_InitIO(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOs clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE
| RCC_AHB1Periph_GPIOF | RCC_AHB1Periph_GPIOG, ENABLE);
/* Common GPIO configuration */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // STM32F429I Only support speeds up to 90Mhz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/*-- SRAM GPIOs Configuration --------------------------------------------------*/
/*
+-------------------+------------------+-------------------+
| PD14 <-> FMC_D0 | PF0 <-> FMC_A0 | PE0 <-> FMC_NBL0 |
| PD15 <-> FMC_D1 | PF1 <-> FMC_A1 | PE1 <-> FMC_NBL1 |
| PD0 <-> FMC_D2 | PF2 <-> FMC_A2 | PD4 <-> FMC_NOE |
| PD1 <-> FMC_D3 | PF3 <-> FMC_A3 | PD5 <-> FMC_NWE |
| PE7 <-> FMC_D4 | PF4 <-> FMC_A4 | PD7 <-> FMC_NE1 |
| PE8 <-> FMC_D5 | PF5 <-> FMC_A5 |-------------------+
| PE9 <-> FMC_D6 | PF12 <-> FMC_A6 |
| PE10 <-> FMC_D7 | PF13 <-> FMC_A7 |
| PE11 <-> FMC_D8 | PF14 <-> FMC_A8 |
| PE12 <-> FMC_D9 | PF15 <-> FMC_A9 |
| PE13 <-> FMC_D10 | PG0 <-> FMC_A10 |
| PE14 <-> FMC_D11 | PG1 <-> FMC_A11 |
| PE15 <-> FMC_D12 | PG2 <-> FMC_A12 |
| PD8 <-> FMC_D13 | PG3 <-> FMC_A13 |
| PD9 <-> FMC_D14 | PG4 <-> FMC_A14 |
| PD10 <-> FMC_D15 | PG5 <-> FMC_A15 |
+-------------------| PD11 <-> FMC_A16 |
| PD12 <-> FMC_A17 |
| PD13 <-> FMC_A18 |
| PE3 <-> FMC_A19 |
+------------------+
*/
//-----------------------------------------
// All pins for Port-D initialization
//-----------------------------------------
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FMC); // PD0 = FMC_D2
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FMC); // PD1 = FMC_D3
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FMC); // PD4 = FMC_NOE
GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FMC); // PD5 = FMC_NWE
// GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_FMC); // PD7 = FMC_NE1
GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_FMC); // PD8 = FMC_D13
GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_FMC); // PD9 = FMC_D14
GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_FMC); // PD10 = FMC_D15
GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FMC); // PD11 = FMC_A16
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FMC); // PD12 = FMC_A17
GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_FMC); // PD13 = FMC_A18
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FMC); // PD14 = FMC_D0
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FMC); // PD15 = FMC_D1
// Structure for Port-D
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5
// | GPIO_Pin_7
| GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10
| GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14
| GPIO_Pin_15;
// Configure Port-D
GPIO_Init(GPIOD, &GPIO_InitStructure);
//-----------------------------------------
// All pins for Port-E initialization
//-----------------------------------------
GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_FMC); // PE0 = FMC_NBL0
GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_FMC); // PE1 = FMC_NBL1
// GPIO_PinAFConfig(GPIOE, GPIO_PinSource3, GPIO_AF_FMC); // PE3 = FMC_A19
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FMC); // PE7 = FMC_D4
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FMC); // PE8 = FMC_D5
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FMC); // PE9 = FMC_D6
GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FMC); // PE10 = FMC_D7
GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_FMC); // PE11 = FMC_D8
GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_FMC); // PE12 = FMC_D9
GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_FMC); // PE13 = FMC_D10
GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_FMC); // PE14 = FMC_D11
GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_FMC); // PE15 = FMC_D12
// Structure for Port-E
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 // | GPIO_Pin_3
| GPIO_Pin_7
| GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11
| GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
// Configure Port-E
GPIO_Init(GPIOE, &GPIO_InitStructure);
//-----------------------------------------
// All pins for Port-F initialization
//-----------------------------------------
GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_FMC); // PF0 = FMC_A0
GPIO_PinAFConfig(GPIOF, GPIO_PinSource1, GPIO_AF_FMC); // PF1 = FMC_A1
GPIO_PinAFConfig(GPIOF, GPIO_PinSource2, GPIO_AF_FMC); // PF2 = FMC_A2
GPIO_PinAFConfig(GPIOF, GPIO_PinSource3, GPIO_AF_FMC); // PF3 = FMC_A3
GPIO_PinAFConfig(GPIOF, GPIO_PinSource4, GPIO_AF_FMC); // PF4 = FMC_A4
GPIO_PinAFConfig(GPIOF, GPIO_PinSource5, GPIO_AF_FMC); // PF5 = FMC_A5
GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_FMC); // PF12 = FMC_A6
GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_FMC); // PF13 = FMC_A7
GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_FMC); // PF14 = FMC_A8
GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_FMC); // PF15 = FMC_A9
// Structure for Port-F
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3
| GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13
| GPIO_Pin_14 | GPIO_Pin_15;
// Configure Port-F
GPIO_Init(GPIOF, &GPIO_InitStructure);
//-----------------------------------------
// All pins for Port-G initialization
//-----------------------------------------
GPIO_PinAFConfig(GPIOG, GPIO_PinSource0, GPIO_AF_FMC); // PG0 = FMC_A10
GPIO_PinAFConfig(GPIOG, GPIO_PinSource1, GPIO_AF_FMC); // PG1 = FMC_A11
GPIO_PinAFConfig(GPIOG, GPIO_PinSource2, GPIO_AF_FMC); // PG2 = FMC_A12
GPIO_PinAFConfig(GPIOG, GPIO_PinSource3, GPIO_AF_FMC); // PG3 = FMC_A13
GPIO_PinAFConfig(GPIOG, GPIO_PinSource4, GPIO_AF_FMC); // PG4 = FMC_A14
GPIO_PinAFConfig(GPIOG, GPIO_PinSource5, GPIO_AF_FMC); // PG5 = FMC_A15
GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, GPIO_AF_FMC); // PG10 = FMC_NE3
GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, GPIO_AF_FMC); // PG12 = FMC_NE4
// Structure for Port-G
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3
| GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_10 | GPIO_Pin_12;
// Configure Port-G
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
//--------------------------------------------------------------
// Internal Function
// Initialize FSMC for the SRAM
//--------------------------------------------------------------
void P_SRAM_InitFMC(void)
{
FMC_NORSRAMInitTypeDef FMC_NORSRAMInitStructure;
FMC_NORSRAMTimingInitTypeDef FMC_NORSRAMTimingInitStructure;
#if 0
// De-initialize for re-initialize
FMC_NORSRAMDeInit(FMC_Bank1_NORSRAM3); // From FMC_Bank1_NORSRAM1 -> 3
#endif
/* Enable FMC clock */
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FMC, ENABLE);
//-----------------------------------------
// Structure for Timing
//-----------------------------------------
FMC_NORSRAMTimingInitStructure.FMC_AddressSetupTime = SRAM_FMC_AST; // 3
FMC_NORSRAMTimingInitStructure.FMC_AddressHoldTime = SRAM_FMC_AHT; // 0
FMC_NORSRAMTimingInitStructure.FMC_DataSetupTime = SRAM_FMC_DST; // 3
FMC_NORSRAMTimingInitStructure.FMC_BusTurnAroundDuration = 0;
FMC_NORSRAMTimingInitStructure.FMC_CLKDivision = 0;
FMC_NORSRAMTimingInitStructure.FMC_DataLatency = 0;
FMC_NORSRAMTimingInitStructure.FMC_AccessMode = FMC_AccessMode_A;
//-----------------------------------------
// Structure for Bank-1 / PSRAM-1
//-----------------------------------------
FMC_NORSRAMInitStructure.FMC_Bank = FMC_Bank1_NORSRAM3; // From FMC_Bank1_NORSRAM1 -> 3
FMC_NORSRAMInitStructure.FMC_DataAddressMux = FMC_DataAddressMux_Disable;
FMC_NORSRAMInitStructure.FMC_MemoryType = FMC_MemoryType_SRAM; // Workaround for 'Free GPIO Pin' <- NOR
FMC_NORSRAMInitStructure.FMC_MemoryDataWidth = FMC_NORSRAM_MemoryDataWidth_16b;
FMC_NORSRAMInitStructure.FMC_BurstAccessMode = FMC_BurstAccessMode_Disable;
FMC_NORSRAMInitStructure.FMC_AsynchronousWait = FMC_AsynchronousWait_Disable;
FMC_NORSRAMInitStructure.FMC_WaitSignalPolarity = FMC_WaitSignalPolarity_Low;
FMC_NORSRAMInitStructure.FMC_WrapMode = FMC_WrapMode_Disable;
FMC_NORSRAMInitStructure.FMC_WaitSignalActive = FMC_WaitSignalActive_BeforeWaitState;
FMC_NORSRAMInitStructure.FMC_WriteOperation = FMC_WriteOperation_Enable;
FMC_NORSRAMInitStructure.FMC_WaitSignal = FMC_WaitSignal_Disable;
FMC_NORSRAMInitStructure.FMC_ExtendedMode = FMC_ExtendedMode_Disable;
FMC_NORSRAMInitStructure.FMC_WriteBurst = FMC_WriteBurst_Disable;
FMC_NORSRAMInitStructure.FMC_ReadWriteTimingStruct = &FMC_NORSRAMTimingInitStructure;
FMC_NORSRAMInitStructure.FMC_WriteTimingStruct = &FMC_NORSRAMTimingInitStructure;
// Configure FSMC
FMC_NORSRAMInit(&FMC_NORSRAMInitStructure);
// Enable Bank-1 / PSRAM-1
FMC_NORSRAMCmd(FMC_Bank1_NORSRAM3, ENABLE); // From FMC_Bank1_NORSRAM1 -> 3
}
//--------------------------------------------------------------
// Sends 16-bit value to the external SRAM
//--------------------------------------------------------------
void UB_SRAM_Write(uint32_t adr, uint16_t wert)
{
// Transfer 16-bits data to the memory
*(uint16_t *) (SRAM_ADR + adr) = wert;
}
//--------------------------------------------------------------
// Reads 16-bit value from the external SRAM
//--------------------------------------------------------------
uint16_t UB_SRAM_Read(uint32_t adr)
{
uint16_t ret_wert = 0;
// Read 16-bits data from the memory
ret_wert = *(__IO uint16_t*) (SRAM_ADR + adr);
return(ret_wert);
}
Is there any missing points that I should check before doing this?
From a software perspective you've got a mismatch between your bank selection and your base address. The FMC banks are arranged as 4x64Mb (banks 1,2,3,4) with the following base addresses:
bank 1: 0x60000000
bank 2: 0x64000000
bank 3: 0x68000000
bank 4: 0x6C000000
It's confusing that ST refer to the 64Mb ranges as banks themselves when they are really sub-banks of the larger bank #1 that's allocated to NOR/PSRAM.
You've defined this:
#define SRAM_ADR ((uint32_t)0x60000000)
// [...]
FMC_NORSRAMCmd(FMC_Bank1_NORSRAM3, ENABLE);
As you can see you've got a mismatch between bank selection (#3) and base address selection (#1). You need to get them aligned.
If you continue to have issues after fixing this then look at your timing calculations and definitely the electrical connections.

Resources