News:

Let's find out together what makes a PIC Tick!

Main Menu

PCM1808

Started by Ecoli-557, Dec 04, 2024, 08:23 PM

Previous topic - Next topic

Ecoli-557

Hello, 1st time poster and new to this compiler.
I want to use a PCM1808 chip in a little project but am not sure how to start this.
I want to use an 18F67K40 as the proc and also eventually use a UDA1334 to play the incoming audio data.
Any help would be greatly appreciated.

RGV250

Hi,
I don't think I2S (PCM1808 IC) is supported natively by Positron but I think I have seen it mentioned on the forum so I would start searching to see if anyone has posted example code for it.

Bob

Pepe

#2
Look PIC24FJ128GA204 or PIC24FJ128GA606 or dsPIC33FJ128GP706
https://www.feasycom.com/the-difference-between-i2c-and-i2s.html

Stephen Moss

Quote from: Ecoli-557 on Dec 04, 2024, 08:23 PMHello, 1st time poster and new to this compiler.
I want to use a PCM1808 chip in a little project but am not sure how to start this.
Although boring, perhaps it would be wise to get accustomed to using the compiler first before jumping straight in to a project the by you own admission you appear to be ill equipped to attempt and simply crossing you fingers that someone has already solved the problem for you.

I presume your intention is to capture the data and store it in the PIC EEPROM space for replay at a later time, in which case why not try something simpler first, like capturing a simple signal using the PIC's ADC and storing that data, then displaying the stored data on a display either as a value or by plotting the resulting waveform on a Graphic display.
Between the answers to question already posed here, the user manual examples and the sample programs provided with the compiler it should be possible for you to get something working, by then you will have gained experience in some of the aspects required for your intended project that will subsequently help you with that, while removing the added complexity of initially having to simultaneously learn/understand how the other devices you want to use work at the same time.

top204

#4
Hello Steve (Ecoli-557), and welcome to the forum.

24-bits is an extreme for audio, and is actually studio quality!

For general purpose, and good quality audio, 12-bits is a good resolution.

If a bit extra resolution is required, it is possible to over-sample the 12-bit ADC value using software, or use one of the dsPIC33 devices that have a better ADC peripheral, and a built in 16-bit DAC peripheral.

Then storage can be made to a flash memory chip or an SD card using Trastikata's modified SD card library. Then all that is required is a couple of op-amps to act as low-pass filters for the input and output signals.

With the Positron compiler, it can all be done with a single 8-bit or 16-bit PIC microcontroller for the control, and a piece of flash memory for the storage, with a couple of analogue devices for the signal conditioning, and I know because I created one a few years ago. The audio quality is excellent, and very controllable. i.e. Speeded up, slowed down, played in reverse, played with an echo etc, all with a single PIC18F device operating with its internal 64MHz oscillator for the control unit, and using double buffering with two RAM arrays for the ADC sampling so it allows time for the flash memory to write without loosing any audio bandwidth!


Ecoli-557

Thanks to All who have answered.  As for just jumping in, yes, your suggestion is good and perhaps I may start crawling, however, I have used PBP Gold since it came our and for decades before.  This compiler looks much like what I am used to - even the IDE!
I am hoping that I can get this quickly - or perhaps wishful thinking?
And, yes, I was hoping someone had already figured it out - then I can also learn by looking at the code.
Good point on number of bits, I just need 12 or perhaps no more than 16 - it is just for speech, so a very narrow bandwidth.
I want to digitize speech and eventually ship out over ethernet - I know its weird.
Top204, your audio project sounds very close to what I am attempting.  What analog chips did you use if I may ask?

top204

#6
The project was quite a few years ago, and commercial, so I cannot give too many details. However, the microcontroller was a PIC18F26K22, then a PIC18F26J11, and the flash memory device was an S25FL208K chip, because only a few 10s of seconds of audio was required, and flash memory chips were then quite expensive for some of the larger ones. The 10-bit ADC was over-sampled to give 12-bit resolution because the 12-bit ADC peripherals were not available on suitably priced devices then.

The analogue devices were a couple of LM358 op-amps to act as an input pre-amplifier and low-pass filter for the ADC input, and the output was two of the PWM channels combined to give a higher resolution DAC operating at a fundamental frequency of 62KHz, so well out of the range of audio interference, and the 12-bit audio samples scaled up to 16-bits using software that fed one of the LM358 op-amp chips working as an integrator and low pass filter and small amplifier.

To get the audio nicely balanced in the ADC, use a variable pot to give a voltage on the +Vref pin, and set the ADC to use the +VRef, and adjusting the voltage to that pin will bring the audio nice and clear. The potentiometer can then be replaced with a pair of resistors when the perfect voltage is known, or kept in place for different input voltages from different op-amp configurations. i.e. Inverted or not-inverted, or different gains and voltage swings etc...

Below is the library I created all of those years ago for the S25FL208K Flash memory chip, and because it has a 256 byte page in it, a double audio buffer was used that only required a pair of 256 word RAM arrays, so when one is being written too with ADC samples, the other is being written to the flash memory as a page, then swap the RAM arrays buffers when one is completed, over, and over, and over. i.e. Double buffered. Note that for different devices, the MSSP peripheral's bits within the SFRs will need to be altered, because microchip keep moving things around in their peripherals for different devices, for some reason!

The same for playback if other things need to be done in the playback interrupt, so while a RAM buffer is being played via the DAC and possibly manipulated, the other RAM buffer is being loaded from Flash memory etc... Then swap when the RAM buffer being played is completed. If a higher audio bandwidth is required, use a triple buffered mechanism that will require another RAM array, so the flash memory has plenty of time to write a page and no audio is lost or clicking heard etc...

This is especially true if using a FAT mechanism on an SD card for recording or playing back, because the FAT mechanism is not exactly lighting fast itself, then the wait for the SD card's page write if recording. But a double or triple buffer works excellently and the code to perform it is surprisingly simple and straightforward by moving the address of the RAM array to write or read from.

$ifndef __S25FL208K__
$define __S25FL208K__
'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' S25FL208K 8-Mbit/1024 kbyte flash memory chip interface for a PIC18F26J11 device.
' Written by Les Johnson for the Positron8 BASIC compiler.
'
$ifndef False
    $define False 0
$endif
$ifndef True
    $define True 1
$endif

$define cS25FL_AmountOfPages 4096           ' The amount of pages within the S25FL208K flash memory chip
$define cS25FL_PageSize      256            ' The size of the page within the S25FL208K flash memory chip

$define cCMD_WriteEnable        $06
$define cCMD_WriteDisable       $04
$define cCMD_Read_Status        $05         ' (S7-S0)
$define cCMD_Write_Status       $01         ' (S7-S0)
$define cCMD_Read_Data          $03         ' Required A23-A16, A15-A8, A7-A0 (D7-D0) (next byte) continuous
$define cCMD_Fast_Read          $0B         ' Required A23-A16 A15-A8, A7-A0, dummy byte, (D7-D0), (Next byte) continuous
$define cCMD_Page_Program       $02         ' Required A23-A16 A15-A8, A7-A0, (D7-D0), (Next byte) Up to 256 bytes
$define cCMD_Block_Erase        $D8         ' (64 kB) Required A23-A16, A15-A8, A7-A0
$define cCMD_Sector_Erase       $20         ' (4 kB) Required A23-A16, A15-A8, A7-A0
$define cCMD_Chip_Erase         $C7         ' Or can use $60
$define cCMD_Power_Down         $B9
$define cCMD_Release_Power_Down $AB         ' Also Device ID: Dummy Byte, Dummy Byte, Dummy Byte, (ID7-ID0)
$define cCMD_Device_ID          $90         ' Dummy byte, Dummy byte, $00, (M7-M0), (ID7-ID0)
$define cCMD_JEDEC_ID           $9F         ' (M7-M0)Manufacturer, (ID15-ID8) Memory Type, (ID7-ID0) Capacity
$define cDummy_Byte             $00

$define cSRP_Bit 7                          ' Status register bit
$define cREV_Bit 6                          ' Status register bit
$define cBP3_Bit 5                          ' Status register bit
$define cBP2_Bit 4                          ' Status register bit
$define cBP1_Bit 3                          ' Status register bit
$define cBP0_Bit 2                          ' Status register bit
$define cWEL_Bit 1                          ' Status register bit
$define cWIP_Bit 0                          ' Status register bit
'
' Setup the default SPI pins to the S25FL208K flash memory chip, if they are not used in the main program listing
'
$ifndef SPI_CS_Pin
    $define SPI_CS_Pin PORTB.7              ' The CS pin to the S25FL208K flash memory chip
$endif

$ifndef SPI_SCK_Pin                        
    $define SPI_SCK_Pin PORTC.3             ' Connects to the SCK pin of the S25FL208K flash memory chip
$endif

$ifndef SPI_SI_Pin                        
    $define SPI_SI_Pin PORTC.4              ' Connects to the SO pin of the S25FL208K flash memory chip
$endif

$ifndef SPI_SO_Pin                        
    $define SPI_SO_Pin PORTC.5              ' Connects to the SI pin of the S25FL208K flash memory chip
$endif

    Dim bStatusValue As Byte                ' Holds the value read from the status register of the flash memory chip
    Dim bManufacturer_ID As Byte            ' Holds the manufacturer value read from the flash memory chip (should be $01)
    Dim bMemory_Type_ID As Byte             ' Holds the Memory Type value read from the flash memory chip (should be $13)

    Dim S25FL_wArrayAddress As Word Access          ' Holds the address of the RAM array to read and write to
    Dim S25FL_bIndex As Byte Access                 ' Used for counting bytes within a page or array etc...
    Dim S25FL_wSectorBlock As Word Access           ' Holds the sector or the block
    Dim S25FL_dSectorBlockAddress As Dword Access   ' Holds the sector or the block address

    Dim S25FL_wFSR0 As FSR0L.Word

'-----------------------------------------------------------------------------------------------
$define S25FL_CS_Enable() PinClear SPI_CS_Pin
$define S25FL_CS_Disable() PinSet SPI_CS_Pin

'-----------------------------------------------------------------------------------------------
' Open the SPI peripheral to talk to the S25FL208K flash memory chip for a PIC18F26J11 device
' Input     : None
' Output    : None
' Notes     : SPI_FOSC_16, MODE_00, SMPMID
'
Proc S25FL_SPI_Open()
    SSPSTATbits_SMP = 0             ' Input data sampled at middle of data output time
    SSPSTATbits_CKE = 1             ' Output data changes on clock transition from active to idle
    PinOutput SPI_SCK_Pin           ' Make the CLK pin an output
    PinInput SPI_SI_Pin             ' Make the Din pin an input
    PinOutput SPI_SO_Pin            ' Make the Dout pin an output
    SSPCON1 = %00100001             ' Enable SPI Master mode. Clock = FOSC/16
EndProc

'-------------------------------------------------------------------------------------------
' Read the status register from the S25FL208K flash memory chip, inline
' Input     : None
' Output    : pResult holds the status value
' Notes     : Status Register Bit Locations:
'           : R7  R6  R5  R4  R3  R2  R1  R0
'           : SRP REV BP3 BP2 BP1 BP0 WEL WIP
'           :   When the WIP bit is set to 1, the device is busy performing an operation.
'           :   When the bit is cleared to 0, no operation is in progress.
'           :   The WEL bit is cleared to 0 at the end of any successful program, write, or erase operation.
'           :   After a power down/power up sequence, hardware reset, or software reset, the Write Enable Latch is set to a 0.
'           :   BP3, BP2, BP1 and BP0 are Block Protect Bits.
'           :   REV is Reserved Bits for future use
'           :   When the SRP bit is set to a 0 state (factory default) the WP# pin has no control over status register.
'           :   When the SRP pin is set to a 1, the Write Status Register instruction is locked out while the WP# pin is low.
'           :   When the WP# pin is high the Write Status Register instruction is allowed.
'
$define S25FL_ReadStatus(pResult)      '
    S25FL_CS_Enable()                  '
    S25FL_hWriteByte(cCMD_Read_Status) '
    S25FL_hReadByte(pResult)           '
    S25FL_CS_Disable()

'-----------------------------------------------------------------------------------
' Write a single Byte to the SPI bus for a PIC18F26J11 device, inline
' Input     : Single 8-bit variable for SPI bus.
' Output    : Input data can be picked up by reading SSPBUF
' Notes     : None
'
$define S25FL_hWriteByte(pDataOut)   '
    SSPSTATBits_BF = 0               '
    PIR1bits_SSPIF = 0               '
    SSPBUF = pDataOut                '
    Repeat: Until PIR1bits_SSPIF = 1

'-----------------------------------------------------------------------------------
' Read a single Byte from the SPI bus for a PIC18F26J11 device, inline
' Input     : None
' Output    : Contents of SSPBUF register
' Notes     : None
'
$define S25FL_hReadByte(pResult)     '
    WREG = SSPBUF                    '
    PIR1bits_SSPIF = 0               '
    SSPBUF = $FF                     '
    Repeat: Until PIR1bits_SSPIF = 1 '
    pResult = SSPBUF

'-----------------------------------------------------------------------------------
' Write a Word to the SPI bus, inline
' Input     : 16-bit variable for SPI bus.
' Output    : None
' Notes     : Writes are Least Siginificant Byte first
'
$define S25FL_hWriteWord(pDataOut)   '
    S25FL_hWriteByte(pDataOut.Byte0) '
    S25FL_hWriteByte(pDataOut.Byte1)

'-----------------------------------------------------------------------------------
' Read a Word from the SPI bus ,inline
' Input     : None
' Output    : pResult
' Notes     : Reads are Least Siginificant Byte first
'
$define S25FL_hReadWord(pResult)    '
    S25FL_hReadByte(pResult.Byte0)  '
    S25FL_hReadByte(pResult.Byte1)

'-------------------------------------------------------------------------------------------
' Initialise the SPI interface
' Input     : None
' Output    : None
' Notes     : None
'
Proc S25FL_Setup()
    DelayMS 50
    PinHigh SPI_CS_Pin                      ' Disable the SPI interface
    S25FL_SPI_Open()                        ' Setup the SPI peripheral to talk to the flash memory chip
EndProc

'-------------------------------------------------------------------------------------------
' Set Write Enable on the S25FL208K flash memory chip
' Input     : None
' Output    : None
' Notes     : None
'
Proc S25FL_Enable_Writes()
    S25FL_CS_Enable()
    S25FL_hWriteByte(cCMD_WriteEnable)
    S25FL_CS_Disable()
EndProc

'-------------------------------------------------------------------------------------------
' Clear Write Enable on the S25FL208K flash memory chip
' Input     : None
' Output    : None
' Notes     : None
'
Proc S25FL_Disable_Writes()
    S25FL_CS_Enable()
    S25FL_hWriteByte(cCMD_WriteDisable)
    S25FL_CS_Disable()
EndProc

'-------------------------------------------------------------------------------------------
' Wait for the S25FL208K flash memory chip to be ready
' Input     : None
' Output    : None
' Notes     : Reads the WIP bit from the status register and exits when it is set to 0
'
Proc S25FL_hWaitForReady()
    Do
        S25FL_ReadStatus(WREG)
        If WREG.cWIP_Bit = 0 Then ExitProc
    Loop
EndProc

'-------------------------------------------------------------------------------------------
' Read the device ID from the S25FL208K flash memory chip
' Input     : None
' Output    : bManufacturer_ID holds the manufacturer code ($01)
'           : bMemory_Type_ID holds the memory type value ($13)
' Notes     : None
'
Proc S25FL_Read_DeviceID()
    S25FL_CS_Enable()                                       ' Enable the SPI interface
    S25FL_hWriteByte(cCMD_Device_ID)
    S25FL_hWriteByte($00)
    S25FL_hWriteByte($00)
    S25FL_hWriteByte($00)
    S25FL_hReadByte(bManufacturer_ID)
    S25FL_hReadByte(bMemory_Type_ID)
    S25FL_CS_Disable()                                      ' Disable the SPI interface
EndProc

'-------------------------------------------------------------------------------------------
' Erase a 4K sector from the S25FL208K flash memory chip
' Input     : pSector holds the 4K byte sector to erase
' Output    : None
' Notes     : Erasure takes 50 milliseconds
'
Proc S25FL_Erase_4K(pSector As S25FL_wSectorBlock)
    S25FL_dSectorBlockAddress = pSector * 4096              ' Calculate the address of the 4K sector to erase
    S25FL_Enable_Writes()                                   ' Enable writing to the flash memory chip
    S25FL_CS_Enable()                                       ' Enable the SPI interface
    S25FL_hWriteByte(cCMD_Sector_Erase)                     ' Send the command for a sector erase (4K bytes)
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte2)       ' \
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte1)       ' |  Send the sector address
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte0)       ' /
    S25FL_CS_Disable()                                      ' Disable the SPI interface
    S25FL_hWaitForReady()                                   ' Wait for the sector to be erased
EndProc

'-------------------------------------------------------------------------------------------
' Erase a 64K block from the S25FL208K flash memory chip
' Input     : pBlock holds the 64K byte block to erase
' Output    : None
' Notes     : Erasure takes 500 milliseconds
'
Proc S25FL_Erase_64K(pBlock As S25FL_wSectorBlock)
    S25FL_dSectorBlockAddress = pBlock * 65536              ' Calculate the address of the 64K block to erase
    S25FL_Enable_Writes()                                   ' Enable writing to the flash memory chip
    S25FL_CS_Enable()                                       ' Enable the SPI interface
    S25FL_hWriteByte(cCMD_Block_Erase)                      ' Send the command for a block erase (64K bytes)
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte2)       ' \
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte1)       ' |  Send the block address
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte0)       ' /
    S25FL_CS_Disable()                                      ' Disable the SPI interface
    S25FL_hWaitForReady()                                   ' Wait for the block to be erased
EndProc

'-------------------------------------------------------------------------------------------
' Erase all the memory from the S25FL208K flash memory chip
' Input     : None
' Output    : None
' Notes     : Erasure takes 7 seconds
'
Proc S25FL_Erase_Chip()
    S25FL_Enable_Writes()                                   ' Enable writing to the flash memory chip
    S25FL_CS_Enable()                                       ' Enable the SPI interface
    S25FL_hWriteByte(cCMD_Chip_Erase)                       ' Send the command to erase the flash memory chip
    S25FL_CS_Disable()                                      ' Disable the SPI interface
    S25FL_hWaitForReady()                                   ' Wait for the chip to be erased
EndProc

'-------------------------------------------------------------------------------------------
' Write to a 256 page on the S25FL208K flash memory chip
' Input     : pBuffAddr holds the address of the array to write to the flash memory chip
'           : pPage holds the page to write to the flash memory chip
' Output    : None
' Notes     : Takes 1.5ms for the page write to occur
'
Proc S25FL_WritePage(ByRef pBuffAddr As S25FL_wArrayAddress, pPage As S25FL_wSectorBlock)
    pBuffAddr = pPage * 256                                 ' Calculate the page to write to as an address
    S25FL_Enable_Writes()                                   ' Enable writing to the flash memory chip
    S25FL_CS_Enable()                                       ' Enable the SPI interface
    S25FL_hWriteByte(cCMD_Page_Program)                     ' Send the command to write a 256 byte page to the flash memory chip
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte2)       ' \
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte1)       ' | Send the address
    S25FL_hWriteByte($00)                                   ' /

    S25FL_wFSR0 = pBuffAddr                                 ' Load FSR0L\H with the address of the array to write from
    For S25FL_bIndex = 255 DownTo 0                         ' Create a 256 byte loop to write to the page
        S25FL_hWriteByte(POSTINC0)                          ' Write a byte to the page
    Next                                                    ' Close the loop
    S25FL_CS_Disable()                                      ' Disable the SPI interface
    S25FL_hWaitForReady()                                   ' Wait for the page to be written
EndProc

'-------------------------------------------------------------------------------------------
' Read from a 256 page on the S25FL208K flash memory chip
' Input     : pPage holds the page to read from the flash memory chip
' Output    : pBuffAddr holds the address of the array to read into from the flash memory chip
' Notes     : None
'
Proc S25FL_ReadPage(ByRef pBuffAddr As S25FL_wArrayAddress, pPage As S25FL_wSectorBlock)
    pBuffAddr = pPage * 256                                 ' Calculate the page to read from, as an address
    S25FL_CS_Enable()                                       ' Enable the SPI interface
    S25FL_hWriteByte(cCMD_Read_Data)                        ' Send the command to read a 256 byte page from the flash memory chip
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte2)       ' \
    S25FL_hWriteByte(S25FL_dSectorBlockAddress.Byte1)       ' / Send the address
    S25FL_hWriteByte($00)                                   ' And the byte within the page

    S25FL_wFSR0 = pBuffAddr                                 ' Load FSR0L\H with the address of the array to write to
    For S25FL_bIndex = 255 DownTo 0                         ' Create a 256 byte loop to read from the page
        S25FL_hReadByte(POSTINC0)                           ' Read a byte from the flash chip and load it into the array
    Next                                                    ' Close the loop
    S25FL_CS_Disable()                                      ' Disable the SPI interface
EndProc

'-------------------------------------------------------------------------------------------
_S25FL208K_Main_:

$endif  ' __S25FL208K__

By the way Steve, it is Les here. i.e. top204, and many thanks for buying the compilers. :-)

John Lawton

Les, have you ever explained why you are "top204", just curious?

John

top204

#8
The TOP20x range, were a component used in the later 'Pace' satellite receivers switch-mode power supplies in the mid 1990s, when I worked for Sky, repairing satellite receivers in Washington (UK). Along with BUZ80 MOSFETs etc... I can honestly say, hand on heart, those 6 years were the best working years of my life. I worked in a little room with 6 other lads and it was like going to work in a social club each day. :-) We had fun telling jokes all day long and just getting on with life's fun, and putting the world to right, and working when not laughing. Then going out on a weekend to Newcastle together for a pub crawl.

They were good lads, and some of them I still keep in touch with over distance because they still live in the North East, and they have all said exactly the same thing. It was just sad that they moved the repair base to Thirsk in yorkshire, so it was too far to travel from the North East each day. :-( However, even though I live in the Fenlands of the UK, at heart I am still 'a Geordie'... "Whaay aaye marra, am gaan yhem noo"! Believe it or not, that is an english dialect from the North East of England, and how I used to speak before I moved away from the North East all of those years ago, and still do sometimes when things get on top of me. :-)

So when the internet came along in the mid 1990s, I took the top200, then top204 name, and it stuck. :-)

Ecoli-557

#9
Great info and story Les.
After much more digging, I have decided to go withy a traditional CODEC approach.  I have my eyes set on a WM8940 but I must say, I have a few things to learn about I2S and a CODECs use - many Adult Beverages will be needed <grin>.
If any one has experience with a WM8940, and would like to Mentor, let me know.
Much out there for a WM8960 which is stereo and I don't need/want.
Just a digital ethernet enabled intercom......
AND, you are welcome Les, I look forward to working with this compiler and learning!

normnet

#10
Cleared post due to corrupted download file.