How do I synchronize my master with slave using Spi communication? I have generated one more Real time clock(apart from miso,mosi,cs,sck) of 10 ms from master and now I have to sync my slave for each raising edge of the clock, slave has to start reading the data from the senor ( lets from ADC ) and using the time slice (for each 2.5 ms) master request for the data, if slave has the data it will send. Now my problem is in main() i should use while(1) (or should I?) when it reading the data i am not able to make out how much time it will take to read. Is there any other solution for sychronization ? ( I am using LPC1343)
Usually SPI ADC are configured to autonomously sample data and flip a IO to indicate to master that data is available, that is captured by an IO interrupt.
If you want your SPI Slave to work synchronously, you have to tell him "sample now" each 10ms. It is called polling.
Your timer interrupt should call a routine that will trigger the polling mechanism.
Related
I am trying to implement a SSI Slave Protocol on a STM32 Board. Since the STM32 Boards don't have a SSI interface, I used its SPI interface in Slave(Transmit only mode). The master SSI sends 24 clock signals and the slave reacts by sending its data(3 Bytes) over the MISO pins. The problem I am facing is that the data is always shifted on the left on every clock signal coming from the master. For example assuming I am constantly sending 0x010101 from slave.
At first transmission the master receives 0x010101
At Second transmission the master receives 0x020202
At third transmission the master receives 0x040404
Can someone please give me some hints on how to solve this problem?
The data-shift with each transmission can happen when the SPI slave recognizes an (unexpected) additional clock pulse. Looking at the SSI protocol description on Wikipedia this actually makes sense:
In order to transmit N bits of data the master emits N clock cycles, followed by another clock pulse to signal the end of the transfer (so-called "Monoflop Time" - referring to the original hardware implementation of the SSI interface). Since the SPI protocol / SPI slave does not know about this additional clock pulse, it begins to output the first bit of the next data byte, which is in turn not recognized by the SSI master. As a result this leads to a shift in the data bits recognized by the SSI master on the next SSI frame.
Unfortunately, it is not easy to handle the Monoflop time correctly with the SPI slave. In order to deal with the additional clock pulse, we could try to set the SPI frame size to 25 bits on the slave side. Since the STM32 hardware only supports SPI frame sizes between 4 bit and 16 bit, the only choice is to set it to 5 bit. This is not very convenient, since we need to convert the 3 byte (24 bit) output data into 5 blocks of 5 bit (24 bit output data + 1 bit dummy data), but it should work for a "normal" transfer.
Things get more complicated though, if we also want to handle the cases "Multiple transmissions" and "Interrupting transmission" correctly. We need to monitor the clock signal to be able to detect the monoflop timeout. This can be done using a STM32 hardware timer with an external trigger. When the timer expires, we need to reset the SPI unit (in order to handle an interrupted transmission) and update the output value. This "simple" task can be quite challenging since it requires a couple of instructions - requiring a fast MCU depending on the SSI clock frequency.
Alternatively the SSI protocol can be implemented using a software-only "bit banging" solution. But this requires a fast MCU as well in order to handle a fast SSI clock correctly.
IMHO the best solution is to use a small (inexpensive) FPGA to implement the SSI slave and let the MCU feed it with data over a traditional SPI interface.
I'm attempting to create a data logger that intakes data from a sensor node with three modalities and transmits that data using three different SPI busses to a Nucleo-f746zg. I would then like to use DMA peripheral to memory mode to take the incoming data from each bus and put it into one of three buffers that will eventually get written to a USB flash drive using FATFS. I'm having issues initializing the DMA in double buffer mode. When I look at each register it seems to be configured correctly but none of the interrupts fire and the data transfer doesn't occur.
I know that the SPI data is coming in. I initially tried this using interrupts but the data rate was too fast and I was losing data so I pivoted to DMA. The Data, once it's in the register correctly writes to the USB drive as well. I'm using the "LL" drivers for both SPI and DMA.
This is my current DMA initialization code:
uint16_t TEST_BUFFER_0[10000];
uint16_t TEST_BUFFER_1[10000];
LL_DMA_SetChannelSelection(DMA1,LL_DMA_STREAM_3, LL_DMA_CHANNEL_0);
LL_DMA_SetDataTransferDirection(DMA1,LL_DMA_STREAM_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_EnableDoubleBufferMode(DMA1,LL_DMA_STREAM_3);
LL_DMA_SetPeriphIncMode(DMA1,LL_DMA_STREAM_3, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1,LL_DMA_STREAM_3, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1,LL_DMA_STREAM_3, LL_DMA_PDATAALIGN_HALFWORD);
LL_DMA_SetMemorySize(DMA1,LL_DMA_STREAM_3, LL_DMA_MDATAALIGN_HALFWORD);
LL_DMA_DisableFifoMode(DMA1,LL_DMA_STREAM_3);
LL_DMA_SetMemoryAddress(DMA1,LL_DMA_STREAM_3,TEST_BUFFER_1);
LL_DMA_SetMemory1Address(DMA1,LL_DMA_STREAM_3, TEST_BUFFER_0);
LL_DMA_SetDataLength(DMA1,LL_DMA_STREAM_3, 10000);
LL_DMA_SetPeriphAddress(DMA1,LL_DMA_STREAM_3, LL_SPI_DMA_GetRegAddr(SPI2));
LL_DMA_EnableIT_HT(DMA1,LL_DMA_STREAM_3);
LL_DMA_EnableIT_TC(DMA1,LL_DMA_STREAM_3);
LL_DMA_EnableStream(DMA1,LL_DMA_STREAM_3);
LL_SPI_EnableDMAReq_RX(SPI2);
LL_SPI_Enable(SPI2);
I'm not seeing either of the interrupts firing nor am I seeing my buffers get full. I'm not one hundred percent sure what actually initiates the DMA transfer other than the documentation alluding to this occurring automatically when data comes in. I'm kind of stuck at this point and I'm not sure what else to try.
I'm writing a custom high-speed Linux SPI driver for an embedded SoC. To send data to the SPI peripheral (DMA_MEM_TO_DEV) I'm the Linux DMA Engine API.
https://www.kernel.org/doc/Documentation/dmaengine/client.txt
Based on the documentation, the steps for setting up and executing a DMA transaction are:
Allocate a DMA slave channel : dma_request_channel
Set slave and controller specific parameters : dmaengine_slave_config
Get a descriptor for tranesaction : dmaengine_prep_slave_single
Submit the transaction : dmaengine_submit
Issue pending requests and wait for callback notification : dma_async_issue_pending
I have this working for single DMA transactions. But I need to send multiple DMA transactions from the same memory location (dma_addr_t buf) of the same size (size_t len) based on some hardware flow control (GPIOs).
For starters, I tried to redo step 1-5 for every DMA transaction. So every time the flow control GPIO IRQ triggers, I reallocate a DMA slave channel, re-set the slave and controller specific parameters, ...
This seems to work too, but I am not sure if it's the most efficient way.
I am wondering if I can just re-submit the transaction again (dmaengine_submit) and issue again (dma_async_issue_pending)? Would this be more efficient?
I can't seem to find any information on how to resubmit the exact same DMA request anywhere in the kernel documentation.
Steps 1 and 2 need not be repeated. Steps 3 to 5 can be repeated for multiple transactions. For example, see the patch here. dspi_dma_xfer function can call dspi_next_xfer_dma_submit multiple times and steps 3 to 5 are redone. Since you want the dma_addr_t buf to be the same, as far as I understand this is what you want.
You need to at least re-init the memory source address, destination address, and length registers as they will change over the course of the DMA transaction. I think it would be just as fast to just redo everything each time - its not very much to setup and thus the time spent is minuscule.
I have my first two nodes setup, I have a ZigBee Coordinator API module and a ZigBee End Device API module. I have the end point connected on Analog pins 1-3 with sensors for temp, moisture, and light.
I have the pins D1-3 configured for ADC, and the IR sample rate setting at EA60 for once per 60 seconds.
The frames log on the co-ordinator shows a stream of Explicit RX Indicator frames and Transmit Status frames, but I am seeing no IO Data Sample RX Indicator frames.
Also, I wired an LED to the sleep indicator pin, and it is almost constantly lit, it's certainly not sleeping for a minute at a time.
Any help would be greatly appreciated.
Do the Explicit RX Indicator frames look like they might contain your I/O samples? You might need to set ATAO=0 to receive the 0x92 frame type, but you're probably better off sticking with parsing the Explicit Rx to find the I/O sample payload and using that.
Regarding your sleeping end device, have you configured the various XBee registers to have it sleep? Find the section on sleep in your XBee documentation and read through it entirely -- there are many configuration options. For the ZigBee specification, you'll need to wake up every 7 seconds, even if it's just a short wakeup for the device to ping its parent device and check for network messages.
Finally, make sure you've wired your LED correctly. If the sleep indicator pin is active low, it will be pulled low whenever sleeping. And the end device will be waking for a short amount of time, possibly too short to see on an LED. You could use a scope or a logic analyzer to monitor the pin for changes instead.
I want to setup an application, where a single trigger-factor (compare-match of a timer) shall request mutliple DMA streams (I.e. set new timer-value and send data to SPI)
Is this possible with the STM32F2x µC or have you got an idea for a µC with the following properties:
compare-match free running uint16 timer
~8 DMA channels
SPI HW unit (best would be with 9 chipselects, but these could be simulated via further DMA channels.
clock-frequency >= 80MHz
<=64 pins (I want to set my own layout and >64 is expected to be to complicate
~128kB RAM
~256kB ROM
cheep (developer board ~20-100 EUR, "easy to use" toolchain, complete with JTAG or other programmer (best would be connection via USB)
I'm not sure if I understand what you're asking here, but a single timer channel can be used to trigger two different DMA streams. See Table 22 in Section 9.3.3 of the manual: for instance, TIM2_CH4 can be used to trigger both stream 6 and stream 7. Also, you can configure a timer to be a slave to a second timer, which I believe could be used to make them fire simultaneously, and then you could use the two different timers as a trigger to the DMA peripheral.
Sorry if I'm unable to elaborate further, as I'm more familiar with the STM32F1xx series which doesn't have the concept of streams, only channels.