Merged from external project:
[bertos.git] / bertos / drv / i2s.c
1
2
3 #include "i2s.h"
4
5 #include <drv/timer.h>
6 #include <cfg/macros.h>
7 #include <cfg/log.h>
8 #include <io/arm.h>
9
10 static uint8_t play_buf1[CONFIG_PLAY_BUF_LEN];
11 static uint8_t play_buf2[CONFIG_PLAY_BUF_LEN];
12
13 /* |x|x|CONT|SECOND|FIRST|IS_PLAYING|CUR_BUF| */
14 /* |7|6| 5  |  4   |  3  |     2    | 1   0 | */
15 static uint8_t status;
16 #define CURRENT_BUF     0x03
17 #define IS_PLAYING       2
18 #define FIRST_BUF_FULL   3
19 #define SECOND_BUF_FULL  4
20 #define CONTINUE_PLAY    5
21
22 INLINE bool is_buffer_full(int bv)
23 {
24         return status & BV(bv);
25 }
26
27 uint8_t *i2s_getBuffer(unsigned buf_num)
28 {
29         kprintf("getBuffer start\n");
30         if (status & BV(IS_PLAYING))
31                 return 0;
32
33         if ((buf_num == I2S_FIRST_BUF) && !is_buffer_full(FIRST_BUF_FULL))
34         {
35                 status |= BV(FIRST_BUF_FULL);
36                 kprintf("status [0x%02X]\n", status);
37                 return play_buf1;
38         }
39         else if ((buf_num == I2S_SECOND_BUF) && !is_buffer_full(SECOND_BUF_FULL))
40         {
41                 status |= BV(SECOND_BUF_FULL);
42                 kprintf("status [0x%02X]\n", status);
43                 return play_buf2;
44         }
45         else
46                 return 0;
47 }
48
49 uint8_t *i2s_getFreeBuffer(void)
50 {
51         if (!(status & BV(IS_PLAYING)))
52                 return 0;
53
54         // disable irq
55         // ...
56         // set continue flag
57         // ...
58         // set buf_full flag
59         // ...
60         // enable irq
61         // ...
62         // return the buffer
63
64         if ((status & CURRENT_BUF) == I2S_FIRST_BUF && !is_buffer_full(SECOND_BUF_FULL))
65                 return play_buf2;
66         else if ((status & CURRENT_BUF) == I2S_SECOND_BUF && !is_buffer_full(FIRST_BUF_FULL))
67                 return play_buf1;
68         else
69                 return 0;
70 }
71
72 INLINE void setCurrentBuffer(int buffer)
73 {
74         status &= ~CURRENT_BUF;
75         status |= CURRENT_BUF & buffer;
76 }
77
78 // code irq callback
79 static void i2s_dma_tx_irq_handler(void) __attribute__ ((interrupt));
80 static void i2s_dma_tx_irq_handler(void)
81 {
82         /*
83         if (status & BV(CONTINUE_PLAY))
84         {
85                 kprintf("irq\n");
86                 if ((status & CURRENT_BUF) == I2S_FIRST_BUF)
87                 {
88                         SSC_PTCR = BV(PDC_TXTDIS);
89                         SSC_TPR = (reg32_t)play_buf2;
90                         SSC_TCR = CONFIG_PLAY_BUF_LEN;
91                         SSC_PTCR = BV(PDC_TXTEN);
92
93                         setCurrentBuffer(I2S_SECOND_BUF);
94                         status &= ~BV(FIRST_BUF_FULL);
95                         status &= ~BV(CONTINUE_PLAY);
96                 }
97                 // TODO: refactor.
98                 else
99                 {
100                         SSC_PTCR = BV(PDC_TXTDIS);
101                         SSC_TPR = (reg32_t)play_buf1;
102                         SSC_TCR = CONFIG_PLAY_BUF_LEN;
103                         SSC_PTCR = BV(PDC_TXTEN);
104
105                         setCurrentBuffer(I2S_FIRST_BUF);
106                         status &= ~BV(SECOND_BUF_FULL);
107                         status &= ~BV(CONTINUE_PLAY);
108                 }
109         }
110         */
111         AIC_EOICR = 0;
112 }
113
114 bool i2s_start(void)
115 {
116         SSC_CR = BV(SSC_TXDIS);
117         //kprintf("%08lX\n", SSC_TCMR);
118         timer_udelay(15);
119         SSC_PTCR = BV(PDC_TXTDIS);
120         SSC_TPR = (reg32_t)play_buf1;
121         SSC_TCR = CONFIG_PLAY_BUF_LEN / 2;
122         SSC_PTCR = BV(PDC_TXTEN);
123         /* enable output */
124         SSC_CR = BV(SSC_TXEN);
125
126 //      ASSERT(SSC_PTSR & BV(PDC_TXTEN));
127         /*
128         kprintf("i2s_start start\n");
129         if (status & (BV(FIRST_BUF_FULL) | BV(SECOND_BUF_FULL)))
130         {
131                 setCurrentBuffer(I2S_FIRST_BUF);
132                 SSC_PTCR = BV(PDC_TXTDIS);
133                 SSC_TPR = (reg32_t)play_buf1;
134                 SSC_TCR = CONFIG_PLAY_BUF_LEN;
135
136                 status |= BV(IS_PLAYING);
137                 status |= BV(CONTINUE_PLAY);
138                 kprintf("start: status [0x%02X]\n", status);
139                 SSC_PTCR = BV(PDC_TXTEN);
140
141                 return true;
142         }
143         else
144         {
145                 kprintf("start: buffers are not full\n");
146                 return false;
147         }
148         */
149         return true;
150 }
151
152 // TODO renderlo configurabile
153 #define MCK_DIV 16
154 #define DELAY ((1 << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK)
155 #define PERIOD ((15 << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK)
156 #define DATALEN (15 & SSC_DATLEN_MASK)
157 #define DATNB ((1 << SSC_DATNB_SHIFT) & SSC_DATNB_MASK)
158 #define FSLEN ((15 << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK)
159
160 #define SSC_DMA_IRQ_PRIORITY 5
161
162 void i2s_init(void)
163 {
164         //TODO sistemare i pin
165         PIOA_PDR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_NPCS0);
166         /* reset device */
167         SSC_CR = BV(SSC_SWRST);
168
169         SSC_CMR = MCK_DIV & SSC_DIV_MASK;
170         SSC_TCMR = SSC_CKS_DIV | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F;
171         SSC_TFMR = DATALEN | DATNB | FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
172
173         /* Disable all irqs */
174         SSC_IDR = 0xFFFFFFFF;
175         /* Set the vector. */
176         AIC_SVR(SSC_ID) = i2s_dma_tx_irq_handler;
177         /* Initialize to edge triggered with defined priority. */
178         AIC_SMR(SPI0_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SSC_DMA_IRQ_PRIORITY;
179         /* Enable the SSC IRQ */
180         AIC_IDCR = BV(SSC_ID);
181         /* Enable interrupt on tx buffer empty */
182         SSC_IER = BV(SSC_ENDTX);
183
184         /* enable i2s */
185         PMC_PCER = BV(SSC_ID);
186
187         /* set current buffer to 1 */
188         status = 0x01;
189         for (int i = 0; i < CONFIG_PLAY_BUF_LEN; ++i)
190         {
191                 //uint32_t tmp = 0x5555;
192                 //uint32_t tmp2 = 0x9999;
193                 play_buf1[i] = i;
194                 //play_buf1[i+4] = tmp2;
195         }
196 }
197
198