Thank you Mr.Ivo.
Here I'm trying to porting your code into a newbie language so I can understand how it works.
But I cannot understand how this code works.
static const struct dma_lli blank_lli = {
blanking, (void*)FL_I2STXFIFO, 0, 4
| (1 << 12)
| (1 << 15)
| (2 << 18)
| (2 << 21)
| (0 << 26)
| (0 << 27)
| (0 << 31)
};
And if you please, could you tell me how this link list item made the I2S output keep on emitting zeroes even after DMA?
Thank you for your help.
#include "mbed.h"
#define FL_PCON ((volatile uint32_t *) 0x400FC0C0) // Power Control Registers
#define FL_PCONP ((volatile uint32_t *) 0x400FC0C4) // Power Control For Peripheral Registers
#define FL_CLKSRCSEL ((volatile uint32_t *) 0x400FC10C) // Clock Source Select Register
#define FL_PCLKSEL0 ((volatile uint32_t *) 0x400FC1A8) // Peripheral Clock Selection Register 0
#define FL_PCLKSEL1 ((volatile uint32_t *) 0x400FC1AC) // Peripheral Clock Selection Register 1
#define FL_PLL0CON ((volatile uint32_t *) 0x400FC080) // PLL0 Control Register
#define FL_PLL0FEED ((volatile uint32_t *) 0x400FC08C) // PLL0 Feed Register (for changing in PLL0CON and PLL0CFG to take effect)
#define FL_PLL0STAT ((volatile uint32_t *) 0x400FC088) // PLL0 Status Register
#define FL_PLL0CFG ((volatile uint32_t *) 0x400FC084) // PLL0 Configuration Register
#define FL_CCLKCFG ((volatile uint32_t *) 0x400FC104) // CPU Clock Configuration Register
#define FL_PINSEL0 ((volatile uint32_t *) 0x4002c000) // Pin Function Select Register 0
#define FL_PINSEL4 ((volatile uint32_t *) 0x4002c010) // Pin Function Select Register 4
#define FL_PINMODE0 ((volatile uint32_t *) 0x4002c040) // Pin Mode Select Register 0
#define FL_PINMODE4 ((volatile uint32_t *) 0x4002C050) // Pin Mode Select Register 4
#define FL_PINMODE_OD2 ((volatile uint32_t *) 0x4002C070) // Open Drain Pin Mode Select
#define FL_FIO0DIR ((volatile uint32_t *) 0x2009C000) // Fast GPIO Port Direction Control Register
#define FL_FIO0CLR ((volatile uint32_t *) 0x2009C01C) // Fast Port Output Set Register
#define FL_FIO0SET ((volatile uint32_t *) 0x2009C018) // Fast Port Output Set Register
#define FL_I2STXRATE ((volatile uint32_t *) 0x400A8020) // Transmit Clock Rate Register
#define FL_I2SDAO ((volatile uint32_t *) 0x400A8000) // Digital Audio Output Register
#define FL_I2STXFIFO ((volatile uint32_t *) 0x400A8008) // Transmit FIFO Register
#define FL_PWM1PR ((volatile uint32_t *) 0x4001800C) // PWM Prescale Register
#define FL_PWM1MR0 ((volatile uint32_t *) 0x40018018) // PWM Match Register 0
#define FL_PWM1MR1 ((volatile uint32_t *) 0x4001801C) // PWM Match Register 1
#define FL_PWM1MR2 ((volatile uint32_t *) 0x40018020) // PWM Match Register 2
#define FL_PWM1MCR ((volatile uint32_t *) 0x40018014) // PWM Match Control Register
#define FL_PWM1PCR ((volatile uint32_t *) 0x4001804C) // PWM Control Register
#define FL_DMACConfig ((volatile uint32_t *) 0x50004030) // DMA Configuration Register
#define FL_DMACC0SrcAddr ((volatile uint32_t *) 0x50004100) // DMA Channel 0 Source Register
#define FL_DMACC0DestAddr ((volatile uint32_t *) 0x50004104)// DMA Channel 0 Destination Address
#define FL_DMACC0LLI ((volatile uint32_t *) 0x50004108) // DMA Channel 0 Link List Item Register
// define structure for DMA linked lists
struct dma_lli {
void *source;
void *dest;
struct dma_lli *next;
unsigned int control_word;
};
// some arbitrary blank data for I2S used for blanking
// even after DMA the I2S output will keep on emitting zeroes (= blank)
static unsigned char blanking[32]= {
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0
};
// preset our blanking DMA linked list
extern const struct dma_lli blank_lli;
// blank linked lists ends the DMA cycle (lli=0)
static const struct dma_lli blank_lli = {
blanking, (void*)FL_I2STXFIFO, 0, 4
| (1 << 12)
| (1 << 15)
| (2 << 18)
| (2 << 21)
| (0 << 26)
| (0 << 27)
| (0 << 31)
};
int main() {
*FL_PCONP = 0; // power off all peripherals
*FL_CLKSRCSEL = 1; // select main oscilator as the PLL0 clock source
*FL_PLL0CON = 1; // disconnect PLL0
*FL_PLL0FEED = 0xAA;
*FL_PLL0FEED = 0x55; // feed for PLL0CON changes
while (*FL_PLL0STAT&(1U<<25)); // wait until PLL0CON changes
*FL_PLL0CON = 0; // disabling PLL0
*FL_PLL0FEED = 0xAA;
*FL_PLL0FEED = 0x55; // feed for PLL0CON changes
while (*FL_PLL0STAT&(1U<<24)); // wait until PLL0CON changes
*FL_PLL0CFG = (1U<<16 | 24U); // set N = 2 and M = 25, but PLL0CFG number is set by (N-1) and (M-1) for this purpose
*FL_PLL0FEED = 0xAA;
*FL_PLL0FEED = 0x55; // feed for PLL0CFG changes
*FL_PLL0CON = 1; // enabling PLL0
*FL_PLL0FEED = 0xAA;
*FL_PLL0FEED = 0x55; // feed for PLL0CON changes
while (!(*FL_PLL0STAT&(1U<<24))); // wait until PLL0CON changes
*FL_CCLKCFG = 2; // set cpu divider with 3, number sent tu CCLKCFG is (N-2) where N = 3
while (!(*FL_PLL0STAT&(1U<<26))); // wait until PLL0 locked
*FL_PLL0CON = 3; // connect PLL0
while (!(*FL_PLL0STAT&(1U<<25))); // wait until PLL0CON changes
*FL_PCONP |= (1U<<15); // power up gpio
*FL_PINSEL0 &= ~(3U<<12); // set port0.6 (DIP8) with gpio
*FL_FIO0DIR |= (1U<<6); // set port0.6 (DIP8) with "output"
*FL_FIO0CLR |= (1U<<6); // set port0.6 (DIP8) with "produce low output"
*FL_PCONP |= (1U<<27); // power up i2s
*FL_PCLKSEL1 |= (1U<<22); // select PCLK = CCLK
*FL_PINSEL0 |= (1U<<14); // P0.7 = i2stx_clk
*FL_PINSEL0 |= (1U<<16); // P0.7 = i2stx_ws
*FL_PINSEL0 |= (1U<<18); // P0.7 = i2stx_sda
*FL_I2STXRATE = 4U | (1U<<8); // produce MCLK with X = 1, Y = 4
*FL_I2SDAO = (00U | (0U<<2) | (7U<<6) ); // set 8-bit data i2s, stereo format, ws_halfperiod = 7 or ws 16clk period
*FL_PCONP |= (1U<<6); // power up pwm1
*FL_PCLKSEL0 |= (1U<<12); // select PCLK PWM = CCLK
*FL_PINSEL4 |= (1U<<2); // activate pwm on port 2.1
*FL_PINMODE4 &= ~(3U<<2);
*FL_PINMODE4 |= (2U<<2); // port 2.1 no pull-up pull-down resistor settings
*FL_PINMODE_OD2 |= (1U<<1); // port 2.1 open-drain mode
*FL_PWM1PR |= 3U; // tc is incremented every PR+1 cycles of PCLK PWM, in this case every 4 PCLK PWM resulting 25MHz clock PWM
*FL_PWM1MR0 = 800U; // 800 color clocks
*FL_PWM1MCR &= ~(7U);
*FL_PWM1MCR |= 3U; // interrupt, reset, !stop for MR0
*FL_PWM1MR2 = 16U; //
*FL_PWM1MR1 = 48U; //
*FL_PWM1PCR |= (1U<<2); // double edge controlled mode for PWM2 output
*FL_PWM1PCR |= (1U<<10); // pwm 2 output enabled
*FL_PCONP |= (1U<<29); // power up gpdma
*FL_DMACConfig |= 1U; // enable DMA
while (*FL_DMACConfig & 1) {}; // wait until DMA enabled
*FL_DMACC0SrcAddr = 0x2007C000; // source address is framebuffer, pointer to peripheral SRAM
*FL_DMACC0DestAddr = *FL_I2STXFIFO; // destination address is i2s tx fifo 8x32bit
while (1) {
}
}
Just been skimming through this article, very good work, but how do you get data into the buffer, And what hardware & connections are you using ? I see you using I2S, but I have not found any nice clear examples.
Are you using a shift registor ? Also what screen ? I have a PSP display, that I have almost got working. But cannot get refresh rate anywhere near quick enough.
Cheers Ceri