[Fun with Xianji SPI Peripheral Series No. 8] SPI simulates I2S reception to achieve recording (2)
I. Introduction
In the article " [Fun Xianji SPI Peripheral Series No. 7] SPI Simulates I2S Transmission to Realize Voice Playback (1) ", the overall solution implementation of I2S timing and SPI simulated I2S is explained, and the effect of SPI simulated I2S transmission to realize voice playback is verified. ,
In the article " Xianji SDK Component Series - DMA Manager dma_mgr ", the use of the component DMA manager in the Xianji SDK package is explained, which facilitates unified management of multi-channel DMA, such as self-allocation of DMA channels, unified management of interrupts, etc.
Based on the above two articles, this article cooperates with the DMA manager to verify the recording effect of SPI simulated I2S reception.
For I2S reception, after the reception is turned on, audio data needs to be acquired continuously without interruption. It is best not to require CPU intervention. DMA uses double buffering. When the current buffer is full, it needs to automatically go to the next buffer. When the next buffer is full, it will automatically to the current buffer, so that the latest audio data can be continuously obtained.
Here’s an effect: the video plays the stored recording data. The codec used in this article is wm8978G, but the codec driver is not covered in this article.
2. Plan implementation
(1) DMA chain realizes multi-buffer reception
It needs to be emphasized that using DMA chaining can not only achieve double buffering, but also multiple chain buffering. This article mainly explains the use of double buffering scheme for reception.
1. Introduction to chain transmission function
In Xianji's DMA module, one feature that cannot be ignored is to support chain transmission. The DMA controller can continuously execute a series of predefined DMA transmission tasks, and each task is seamlessly connected without CPU intervention. Chain transfer is usually implemented by setting multiple DMA descriptors (Descriptor). Each descriptor contains all parameters required for the next DMA transfer, such as source address, destination address, transfer length, transfer mode, etc. When the transfer task corresponding to a descriptor is completed, the DMA controller will automatically obtain the address of the next descriptor from the current descriptor and continue with the next round of transfer based on the parameters of the new descriptor.
The benefits of this feature can be imagined, such as the following:
1) No CPU intervention required: During the chain transmission process, the CPU only needs to set up the entire transmission chain at one time, and then it can completely focus on other tasks. There is no need to intervene in setting up the next round of transmission after each DMA transmission. This greatly reduces the CPU's management burden on DMA operations and improves CPU utilization.
2) Gap-free transmission: Chain transmission ensures the continuous and uninterrupted flow of data between different memory areas or devices. For applications that require high bandwidth and low latency, such as audio streaming, video streaming, real-time data collection, etc., this seamless data transmission method can avoid transmission intervals and potential synchronization problems caused by CPU intervention, ensuring data flow continuity and real-time.
3) Simplify complex transmission tasks: Just configure the descriptor chain in advance, and the DMA controller can automatically execute these tasks in sequence without writing complex CPU control logic.
2. Chain transmission function configuration
Using DMA chain transfer, design a chain transfer sequence so that the last descriptor points to the first descriptor, thus forming a closed loop. In this way, once the DMA controller completes the task of the current descriptor and moves to the next one, it will return to the original task to start a new round of transfers.
The block diagram is as follows:
In " Xianji SDK Component Series - DMA Manager dma_mgr ", the dma_mgr_config_linked_descriptor API is provided to generate a predetermined DMA descriptor. From the above block diagram design, assume that A's buffer is buffer0 and B's buffer is buffer1.
1) DMA configuration: Source/destination addresses, different transfer lengths, modes, etc. need to be configured. Here SPI DATA is used as the source address destination, and cache is used as the device address destination.
2) Generate DMA descriptor of A
3) Generate DMA descriptor of B
4) Configure DMA and start transmitting A. The descriptor chain address points to the DMA descriptor of B.
3. Continuously obtain data
After configuring the above settings, since it is a closed-loop transmission, no interrupt is generated when the transmission is completed. How to confirm that the current buffer has been received? The main consideration here is versatility, and other methods can be used to obtain it.
1) Use a timer for timing. The time for this timer is determined by the length of data that needs to be received.
For example, if the sampling rate is 8K, the number of sampling bits is 16 bits (recorded as audio_depth), and the received data length byte is size, then the time of 16 bits (transmission unit) is half of the sampling rate (recorded as actual_fclk_half_rld), according to the transmission unit requirements The unit of transmission is (size / (audio_depth / 8)).
Then the total timing time is:
actual_fclk_half_rld * (size / (audio_depth / 8))
In order to ensure that DMA has been transmitted in a chain and that the current chain has been transmitted, 10 to 20 actual_fclk_half_rld times need to be added. Then the timing can be implemented as follows:
2) Set the receiving callback function to receive in the scheduled interrupt (for the application part, this may not necessarily be done)
You can know the next transfer chain through the chain transfer address of DMA, so you can know which buffer has been received.
If the next chain transfer descriptor address of the current DMA transfer is A, then it means that B is currently transferring and A has been transferred, otherwise it is reversed. The callback function can return the current buffer index.
3) Write to memory, such as SD card, etc. (for the application part, this may not necessarily be done)
Define a two-dimensional array to represent double buffering.
The callback processing is as follows, recording the array index of the completed transmission and reception, and setting the flag rx_flag to indicate that it can be stored.
When rx_flag is set, it is written to the SD card.
In this way, recording can be achieved. Look at the received waveform, the 8K sampling rate is 16 sampling bits.
3. Summary
1. Verify the feasibility of SPI simulation of I2S host transceiver to meet basic audio requirements.
2. Xianji's DMA chain transfer function allows the DMA controller to start the next task immediately after completing one task without waiting for the CPU to be reconfigured. This can maximize the use of bus bandwidth, especially when dealing with high-speed peripherals or large amounts of data, and can effectively improve the system's data throughput capability, which is very helpful when efficient data transmission and continuous uninterrupted data flow are required. of.