Страница 1 из 1

воспроизведение WAV с SD карточки

Добавлено: Вс ноя 08, 2015 16:24:18
Gek0n
Решил немного переписать код плеера от ELM CHaN`а

Соответственно переписал вот такой код:
Спойлер

Код: Выделить всё

; Read and forward a partial data block
;
; void fwd_blk_part (void*, WORD, WORD);

.global fwd_blk_part
.func fwd_blk_part
fwd_blk_part:
	movw	XL, r24			;X = R25:R24 (memory address)
	movw	ZL, r22			;Z = R23:R22 (byte offset in the sector)

	ldi	r18, lo8(514)		;R19:R18 = 514, Number of bytes to receive
	ldi	r19, hi8(514)		;/
	sub	r18, ZL			;R19:R18 -= Z
	sbc	r19, ZH			;/
	sub	r18, r20		;R19:R18 -= R21:R20
	sbc	r19, r21		;/
	; Skip leading data bytes
	ldi	r24, 0b000100		;PB2(SCK)
1:	sbiw	ZL, 1			;Skip leading data...
	brcs	2f			;
	.rept 16			;Discard a byte on SPI
	out	_SFR_IO_ADDR(PINB), r24	;
	.endr				;/
	rjmp	1b			;
2:	sbiw	XL, 0			;Destination?
	breq	fb_wave

fb_mem:	; Store intermediate data bytes to the memory
	rcall	rcv_spi			;do
	st	X+, r24			; *X++ = rcv_spi()
	subi	r20, 1			;while (--r21:r20)
	sbci	r21, 0			;
	brne	fb_mem			;/
	rjmp	fb_exit

fb_wave: ; Forward intermediate data bytes to the wave FIFO
	sbic	_FLAGS, 4		;if (16bit data) R21:R20 /= 2;
	lsr	r21			;
	sbic	_FLAGS, 4		;
	ror	r20			;/
	sbic	_FLAGS, 1		;if (Stereo data) R21:R20 /= 2;
	lsr	r21			;
	sbic	_FLAGS, 1		;
	ror	r20			;/
	lds	r22, FifoWi		;r22 = FIFO write index

3:	ldi	XL, lo8(Buff)		;X = Buff + R22
	ldi	XH, hi8(Buff)		;
	add	XL, r22			;
	adc	XH, r1			;/
4:	lds	r24, FifoCt		;wait while FIFO full
	cpi	r24, 252		;
	brcc	4b			;/
#if MODE >= 1	// Dual output
#if MODE == 2	// Hi-Res
	rcall	rcv_spi			;Get L-ch/Mono data into Z
	clr	ZL			;
	sbis	_FLAGS, 4		;
	rjmp	6f			;
	mov	ZL, r24			;
	rcall	rcv_spi			;
	subi	r24, 0x80		;
6:	mov	ZH, r24			;/
	sbis	_FLAGS, 1		;if Mono data, do not process R-ch data
	rjmp	8f			;/
	rcall	rcv_spi			;Get R-ch data and mix it to Z
	clr	r25			;
	sbis	_FLAGS, 4		;
	rjmp	7f			;
	mov	r25, r24		;
	rcall	rcv_spi			;
	subi	r24, 0x80		;
7:	add	ZL, r25			;
	adc	ZH, r24			;
	ror	ZH			;
	ror	ZL			;/
#else		// Stereo
	sbic	_FLAGS, 4		;Get L-ch/Mono data into ZH, ZL
	rcall	rcv_spi			;
	rcall	rcv_spi			;
	sbic	_FLAGS, 4		;
	subi	r24, 0x80		;
	mov	ZL, r24			;
	mov	ZH, r24			;/
	sbis	_FLAGS, 1		;if Mono data, do not process R-ch data
	rjmp	8f			;/
	sbic	_FLAGS, 4		;Get R-ch data into ZL
	rcall	rcv_spi			;
	rcall	rcv_spi			;
	sbic	_FLAGS, 4		;
	subi	r24, 0x80		;
	mov	ZL, r24			;/
#endif
8:	st	X+, ZL			;Store Z into FIFO
	st	X+, ZH			;/
	cli				;
	lds	r24, FifoCt		;
	subi	r24, -2			;
	sts	FifoCt, r24		;
	sei				;
	subi	r22, -2			;/
#else		// Single output
	sbic	_FLAGS, 4		;Get L-ch/Mono data into ZL
	rcall	rcv_spi			;
	rcall	rcv_spi			;
	sbic	_FLAGS, 4		;
	subi	r24, 0x80		;
	mov	ZL, r24			;/
	sbis	_FLAGS, 1		;if Mono data, do not process R-ch data
	rjmp	8f			;/
	sbic	_FLAGS, 4		;Get R-ch data
	rcall	rcv_spi			;
	rcall	rcv_spi			;
	sbic	_FLAGS, 4		;
	subi	r24, 0x80		;/
	add	ZL, r24			;ZL = (ZL + R-ch) / 2
	ror	ZL			;/
8:	st	X+, ZL			;Store ZL into FIFO
	cli				;
	lds	r24, FifoCt		;
	inc	r24			;
	sts	FifoCt, r24		;
	sei				;
	inc	r22			;/
#endif
	subi	r20, lo8(1)		;while(--R21:R20)
	sbci	r21, hi8(1)		;
	brne	3b			;/
	sts	FifoWi, r22		;Save FIFO write index

fb_exit:
	ldi	r24, 0b000100		;PB2(SCK)
9:	.rept 16			;Discard a byte on SPI
	out	_SFR_IO_ADDR(PINB), r24	;
	.endr				;/
	subi	r18, lo8(1)		;Repeat r19:r18 times
	sbci	r19, hi8(1)		;
	brne	9b			;/

	ret
.endfunc



;---------------------------------------------------------------------------;
; Read and forward the data block
;
; ISR(TIM0_COMPA_vect);


.global TIM0_COMPA_vect
.func TIM0_COMPA_vect
TIM0_COMPA_vect:
	push	r24				;Save regs.
	in	r24, _SFR_IO_ADDR(SREG)		;
	push	r24				;
	push	ZL				;
	push	ZH				;/

	lds	ZL, FifoRi			;Get FIFO read index
	clr	ZH				;Z = pointer to the top of FIFO
	subi	ZL, lo8(-(Buff))		;
	sbci	ZH, hi8(-(Buff))		;/
	lds	r24, FifoCt			;Load FIFO data counter

#if MODE >= 1	// Dual output
	subi	r24, 2				;Check availability of the sampling data
	brcs	9f				;/
	sts	FifoCt, r24			;Save FIFO data counter
	ld	r24, Z+				;Get R-ch/LSB data and send it to PWM
	out	_SFR_IO_ADDR(OCR1A), r24	;/
	ld	r24, Z+				;Get L-ch/MSB data and send it to PWM
	out	_SFR_IO_ADDR(OCR1B), r24	;/
#else		// Single output
	subi	r24, 1				;Check availability of the sampling data
	brcs	9f				;/
	sts	FifoCt, r24			;Save FIFO data counter
	ld	r24, Z+				;Send data to PWM
	out	_SFR_IO_ADDR(OCR1B), r24	;/
#endif
	subi	ZL, lo8(Buff)			;Save FIFO read index
	sts	FifoRi, ZL			;/

9:	pop	ZH				;Restore regs.
	pop	ZL				;
	pop	r24				;
	out	_SFR_IO_ADDR(SREG), r24		;
	pop	r24				;/
	reti
.endfunc
В такой код
Спойлер

Код: Выделить всё

interrupt [TIM1_COMPA] void timer1_compa_isr(void){
	if(CB_Ct > 1){
    	CB_Ct -= 1;
        OCR0A = CB[CB_Ri++]; 
    }                 
}

char CardType;
extern volatile BYTE CB_Ri, CB_Wi, CB_Ct;

#define MODE 0
#define mono 0

void fwd_blk_part(BYTE *dest, WORD offset, WORD count){
    //Байты, которые останутся после заполнения
    //предложенного буфера, но всё равно будут выдаваться картой, так как размер
    //выдаваемых данных кратен 512 байтам
    int skip_counter = 514 - offset - count;
    char res = 0;
    BYTE CB_Wi_buf = CB_Wi;
    //BYTE CB_Wi_buf = 0;
    BYTE recv_byte;
    BYTE buff_byte;

    //Пропускаем такое количество байт, чтобы начать считывать
    //начиная с указанного смещения
    while(offset--){
        res = spi_send(0xFF);
    }

    //Если указали буфер, в который надо считать данные, то считываем
    //указанное от смещения количество байт данных в буфер
    if(dest != NULL){
        do{
            *dest++ = spi_send(0xFF);
        } while(--count);
    } 
    else{
        //Считываем данные в кольцевой буфер для проигрывания
        #ifdef 16_bit
            count /= 2;
        #else
            #ifdef stereo
                count /= 2;
            #endif
        #endif
        dest += CB_Wi_buf;
        do{
            while(CB_Ct < 252); // Ждем, пока буффер заполнится полностью
            #if MODE >= 1 //Вывод на 2 динамика
            #if MODE == 2 //HI-RES

            #else  //STEREO

            #endif
            #else   //Вывод на 1 динамик
                recv_byte = spi_send(0xFF);
                #ifdef 16_bit
                    recv_byte = spi_send(0xFF);
                    recv_byte -= 0x80;
                #endif
                buff_byte = recv_byte;
                #ifndef mono
                    recv_byte = spi_send(0xFF);
                    #ifdef 16_bit
                        recv_byte = spi_send(0xFF);
                        recv_byte -= 0x80;
                    #endif
                    buff_byte = (buff_byte + recv_byte) / 2;
                #endif
                *dest++ = buff_byte;
                #asm("cli");
                CB_Ct++;
                #asm("sei");
                CB_Wi_buf++;
            #endif
        } while (--count);
        CB_Wi = CB_Wi_buf;
    }
    //Пропускаем количество байт, оставшиеся непрочитанными в блоке
    spi_send_cycle(0xFF, skip_counter);
}

Получилось примерно такое рассуждение:
Подрубаем 16 МГц внешний кварц.
Запускаем 0-й счетчик с частотой 16 МГц (без делителя), в режиме FastPWM. Это тот режим когда устанавливаются все 3 бита WGM00:02
Получается что счетчик считает от 0 до указанного в регистре OCR0A значения. Это наша несущая.
Дальше делим 1-й счетчик на 8 - получаем 2 МГц, что дает примерно 8 кГц период выборки. С такой частотой надо доставать новый байт из буфера и отправлять его на проигрывание в регистр OCR0A 0-го счетчика.

Соответственно кольцевой буфер заполняется переписанной мною с ассемблера на СИ функцией fwd_blk_part.

На практике МК заводится, сигналит по UART компу, что карточка инициализирована нормально, что начал читать блоки от 1.WAV файла и потом тишина. Звук быть должен достаточно громкий, чтобы его услышать (знаю так как собирал схему автора на этих же элементах, кроме МК).

Помогите найти ошибку в коде или в логике. Спасибо.

Re: воспроизведение WAV с SD карточки

Добавлено: Вс ноя 08, 2015 20:42:46
DronVolk
Gek0n писал(а):Получается что счетчик считает от 0 до указанного в регистре OCR0A значения
а шим не так работает! Он либо пишет на ногу лог 1 пока счетчик меньше значения в регистре либо 0 и потом меняет значение.

у вас как я понял настроено что максимально значение счетчика OCR0A значит шим будет по OCR0B а его вы не исправляете из вашего описания.

зы код не смотрел.

Re: воспроизведение WAV с SD карточки

Добавлено: Пн ноя 09, 2015 09:45:31
Gek0n
Ну, собственно, да. Я неправильно написал. Действительно меняется 1 на 0 когда досчитает.
Только причем тут OCR0B я не понял

Re: воспроизведение WAV с SD карточки

Добавлено: Пн ноя 09, 2015 19:57:26
Gek0n
Код был неверный. Я исправил. Всё заработало. Спасибо.