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