PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   dsPIC - Bộ điều khiển tín hiệu số 16-bit (http://www.picvietnam.com/forum/forumdisplay.php?f=29)
-   -   máy nghe nhac with Wav(PCM) và sd card (http://www.picvietnam.com/forum/showthread.php?t=6427)

lybao_huy 28-05-2010 12:25 PM

máy nghe nhac with Wav(PCM) và sd card
 
mình đã cơ bản làm xong rồi, mình dùng Dspic33fj64gp804, dùng DAC Module để phát nhạc, nhưng lại gặp một vấn khó giải:

1- Nó phát ra nhạc nhưng lại dứt quãng: lý do dùng hàm Fsread() để đọc file nhạc(một lần đọc 512 byte) rồi đưa nó vào bộ đệm, từ bộ đệm này cho nó lần lượt vào bộ đệm FIFO có Four word deep của DAC, khi hết dữ liệu trong bộ đệm thì tiếp tục dùng hàm Fsread() để đọc và lặp lại mãi, nhưng ác nỗi vì tốc độ truy cập thẻ SD có giới hạn chỉ 10MHz (SPI) nên suy ra đọc 512 Byte cần tối thiểu 409.6us (chưa kể thời gian chờ, ...), trong khi với file nhạc có định dạng 16khz, 16bit và DAC có độ sâu 4 từ , nên suy ra cứ mỗi 250us lại phải nạp dữ liệu vào bộ đệm của DAC, thành thử nó phát ra nhạc nhưng lại ngắt quãng liên tục.

2-mình dùng ngắt cũng không thực hiện được với lý do nêu ở trên, dùng ngắt nó sẽ ảnh hưởng tới hàm Fsread(), nó cứ ngắt liên tục hàm Fsread() thành ra nó không thể đọc dữ liệu từ thẻ SD.

Mong các bạn giúp đỡ.

bien_van_khat 28-05-2010 12:52 PM

Bạn thử cấu hình để dùng DAC với DMA hoặc viết thêm 1 hàm đọc thẻ sử dụng DMA, như vậy sẽ ko phải chờ DAC hoặc SPI

lybao_huy 28-05-2010 01:11 PM

hiện giờ thì theo mình biết cũng không thể dùng DMA vì: DMA nó cũng ngắt để đẩy dữ liệu cho DAC, mà hễ dùng ngắt thì hàm Fsread() sẽ bị ảnh hưởng vì khi đọc 512 byte từ sd card thì phải bảo dảm quá trình này liên tục không thể bị ngắt được. Tôi không biết phải làm thế nào nữa, và nhũng ngừoi khác làm cách nào mà nó chạy tốt quá.

bien_van_khat 28-05-2010 04:07 PM

Chỉ khi nào DMA hoàn tất việc chuyển khối dữ liệu mà bạn yêu cầu thì nó mới sinh ra ngắt.

lybao_huy 30-05-2010 12:31 AM

cảm ơn bạn nhiều lắm, để mình làm thử xem sao. Chỗ mình cúp điện dữ quá

ubuntu7 01-06-2010 11:10 AM

ban thử làm thế này xem sao: khi đọc còn 4byte nữa bạn thực hiện hàm gọi fsread(). như vậy nó sẽ mất t1 thời gian để đọc xong data vào buf, trong thời gian nay ban cũng đọc nốt 4 byte còn lại vào Dac. ngày xưa mình làm với pwm cũng làm theo cách lấy bớt như thế này k bị ngắt, chạy nuột.

lybao_huy 01-06-2010 01:01 PM

Trích:

Nguyên văn bởi ubuntu7 (Post 36456)
ban thử làm thế này xem sao: khi đọc còn 4byte nữa bạn thực hiện hàm gọi fsread(). như vậy nó sẽ mất t1 thời gian để đọc xong data vào buf, trong thời gian nay ban cũng đọc nốt 4 byte còn lại vào Dac. ngày xưa mình làm với pwm cũng làm theo cách lấy bớt như thế này k bị ngắt, chạy nuột.

Theo mình là không thể(cách bạn làm ra sao mình không rõ lắm) vì:
nếu tốc độ lấy mẫu là 48Khz =>cứ 20.83us DAC lại lấy một mẫu và do bộ FIFO 4 từ của DAC suy ra cứ mỗi 4*20.83us=83.32us là phải đẩy dữ liệu vào bộ đệm FIFO ,trong khi đó phải mất ít nhất là 1.4ms để đọc 512 byte từ hàm fsread() và quá trình đọc dữ liệu từ thẻ nhớ là liên tục không bị ngắt, thành ra không thể làm theo cách bạn.
chỉ có cách dùng DMA là khả thi nhất thôi, còn không phải dùng một con IC nào đó như VS1001(bởi vì con này nó có bộ đệm trong khá lớn nên mình đẩy dữ liệu vào bộ đệm của nó rồi mình lại đọc dữ liệu từ thẻ nhớ chờ sẵn khi nào bộ đệm của nó hết mình lại đẩy tiếp thì được) hay con PIC hay là Dspic khác thì ok.
không biết mình nói đúng không(mới nghiên cứu thôi). Do cúp điện và bận nhiều việc nên chưa thể nào làm nhanh được

lybao_huy 02-06-2010 12:49 PM

Mình làm được rồi, chạy rất trơn tru, dùng DMA. mình cảm ơn bạn có ních bien_van_khat nhiều lắm. À mình có một thắc mắc nhỏ là:
Theo như trong datasheet DMA nó có nói là khi một ngắt A mà được chuyển cho DMA thì CPU sẽ không thể ngắt nó được, nhưng mà mình thấy nó vẫn có thể ngắt nó được nếu ngắt A này có khả ngắt. Mong giải thích dùm

bien_van_khat 03-06-2010 01:44 PM

Chưa hiểu ý bạn. Bạn có thể cho biết đoạn đó nằm ở trang nào, datasheet nào??

lybao_huy 04-06-2010 10:00 AM

Trích:

Nguyên văn bởi lybao_huy (Post 36480)
Mình làm được rồi, chạy rất trơn tru, dùng DMA. mình cảm ơn bạn có ních bien_van_khat nhiều lắm. À mình có một thắc mắc nhỏ là:
Theo như trong datasheet DMA nó có nói là khi một ngắt A mà được chuyển cho DMA thì CPU sẽ không thể ngắt nó được, nhưng mà mình thấy nó vẫn có thể ngắt nó được nếu ngắt A này có khả ngắt. Mong giải thích dùm

À không, lúc trước mình đọc chưa kĩ, đọc lại thì thấy mình sai. cảm ơn sự quan tâm của Bạn.

Hiện tại mình phát nhạc với tốc độ lấy ,mẫu 16khz, stereo chạy cực tốt. Do thiếu thạch anh 24.576M, nên chưa thử play nhạc ở tốc độ 48Khz, stereo được .

Nhưng mình tính thấy rằng DMA có 2k Ram , mình cấp cho độ đệm kênh phải RightBufA=128*2 byte( RightBufA có kiểu int) và RightBufB=128*2 byte(RightBuf có kiểu int), và cũng tương tự cho kênh trái LetBufA, LetBufB, chạy DMA ở chế độ repeat,continue,ping-pong và HALF: Block Transfer Interrupt Select bit =0.

Đọc 512 byte từ thẻ nhớ mất khoảng 3.25ms(thực ra nếu đọc 512 byte đã được canh lề đúng thì chỉ mất 1.42ms , nhưng do khi đọc thực tế thì có thể không canh lề đúng vì dữ liều có thể nằm trên 2 sector khác nhau trong 1 lần đọc 512 byte)512 byte này thì RightBufA hoặc RightBufB lấy 128*2 byte và LetBufA hoặc LetBufB lấy 128*2 byte

và vì tốc độ lấy mẫu là 48Khz => cứ 20.833us lại lấy mẫu một lần, và vì RightBufA hay RightBufB,... là 128 => cứ mỗi 20.833us*128 =2.6667ms DMA kênh 0(cho kênh phải) và kế đó là DMA kênh 1(cho kênh trái) lại ngắt một lần. Tóm lại thì sau 2.6667ms thì CPU phải đẩy dữ liệu vào cho cả 2 kênh.

Vậy là không đủ thời gian =>âm thanh sẽ bị ngắt ngãng, chưa tính đến phải xử lý âm thanh. vậy làm sao để giải quyết đây, bạn có cách nào không.

bien_van_khat 04-06-2010 02:48 PM

Vì mỗi lần bạn luôn đọc 512byte, và dữ liệu luôn được sắp xếp theo từng sector 512byte, vậy tại sao lại có trường hợp bạn đọc 512byte ở 2 sector khác nhau??

Ngoài ra đọc 512byte mất 1.42ms => tốc độ đọc ~ 350KB/s, đây là tốc độ khá chậm. Bạn sử dụng tần số SPI bao nhiêu??

lybao_huy 04-06-2010 10:28 PM

mình chạy SPI chạy ở tốc độ 10Mhz => đọc 512 byte mất 409.6us. Lý do là: mình gửi lệnh đọc đơn khối, chờ khoảng 8 clock ,đọc đáp ứng lệnh, sau đó có thể chờ x (micro giây) để đọc token data, sau đó là dữ liêu. mình thấy thế này.

giá trị x này ở một số địa chỉ vật lý có thể chờ lên đến 1.4 mili giây, còn ở một số khác thì chỉ vài trăm micro giây, mình cũng không hiểu có này nữa.

còn đọc 512byte ở 2 sector khác nhau là do: theo cấu trúc của file .wav định dạng PCM thì các mẫu âm thanh bắt đầu ở vị trí offset ví dụ là 44(tính từ đầu file, cũng chính là sector đầu tiên) nên khi ta đọc đúng 512 byte( thu được 256 mẫu âm thanh) thì có 468 byte ở sector này và 44 byte còn lại ở sector bên kia, và tương tự cho các mẫu còn lại. Do vị trí offset này có thể là một số con số khác, nên không thể chỉnh cho việc đọc đúng trong 1 sector được (có thể chỉnh được nhưng mình thấy không hay lắm).

lybao_huy 04-06-2010 10:53 PM

Giá trị x nêu ở trên tôi thử trên 2 thẻ nhớ micro SD, đều cho kết quả tương tự.

bien_van_khat 05-06-2010 07:05 PM

Trích:

Nguyên văn bởi lybao_huy (Post 36530)
mình chạy SPI chạy ở tốc độ 10Mhz => đọc 512 byte mất 409.6us. Lý do là: mình gửi lệnh đọc đơn khối, chờ khoảng 8 clock ,đọc đáp ứng lệnh, sau đó có thể chờ x (micro giây) để đọc token data, sau đó là dữ liêu. mình thấy thế này.

giá trị x này ở một số địa chỉ vật lý có thể chờ lên đến 1.4 mili giây, còn ở một số khác thì chỉ vài trăm micro giây, mình cũng không hiểu có này nữa.

Vì bạn sử dụng lệnh READ_SINGLE_BLOCK 2 lần để đọc 2 sector nên phải tốn 2 lần để chờ Data token.
Nếu bạn muốn đọc >=2 sector tốt nhất nên dùng lệnh READ_MULTIPLE_BLOCK, như vậy chỉ phải chờ Data token 1 lần nên tốc độ đọc sẽ cải thiện hơn rất nhiều.

Thông thường trong truyền thông, quy tắc chung là đọc/ghi 1 lần càng nhiều dữ liệu thì tốc độ càng cao vì giảm overhead.

Nếu bạn muốn tốc độ cao hơn nữa, dùng buffer lớn hơn, đọc nhiều sector hơn trong 1 lần, RAM của con dsPIC bạn dùng lên tới 16KB.

Ngoài ra bạn có thể viết code để lần đầu tiên chỉ đọc và dùng 468byte để xuất âm thanh, còn tất cả các lần còn lại đều dùng 512 byte, như vậy chưa tính việc đọc thẻ, giải thuật cũng đã nhanh hơn đáng kể vì ko cần copy qua lại giữa các buffer.

lybao_huy 05-06-2010 09:41 PM

Cảm ơn bạn nhiều lắm, để mình nghiên cứu thử coi.
Hiện tại mình cũng đang cố tăng tốc độ nó lên và cũng đạt được một số một điều thú vị


Múi giờ GMT. Hiện tại là 12:10 PM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam