Post Go back to editing

BF706 UART DMA Terminal for Audio and FIR filter Control

This has yet to be my most complex Tutorial and I hope not the final one...I call it Audio Filter control. In fact it is many things in one. I have finally achieved UART immortality by being able to control everything from it. I can turn LED on and OFF. Set the BLINK Rate among many different rates, turn Audio ON and OFF and lastly, turn a Cross-Over filter ON or OFF. You might want to turn the LED OFF while the filter is executing or you might get weird feedback. I guess I'm not perfect, so nothing is stopping you from correcting my quickly written code that included the work of brilliant people here on the Forum. @PatrickG and @UweS to mention a few great minds...Lets move on, shall we ?!

This example can be a bit daunting, but it is really quite simple even underneath the surface. I have used Will Pirkle's excellent software called RackAFX to test my prototype whose simple parameters are passed passed in at the console. The only commands you need to know in this incarnation of the software are really: aud on / aud off /filt on / filt off.

Check out my other indepth tutorials for the other commands which are clearly obtained by typing term at the PUTTY terminal i.e.

The terminal is very self explanatory, so go ahead and experiment with the different terminal commands. The neat thing in this version is that you can simply engage a mode of the terminal that works for you by commenting or un-commenting one line at the top of the source! If you used the definition as you see below, it means you are running UART as DMA interrupt device. If you comment the line out you are only running interrupts RX and TX without DMA. The choice is yours! 

 // Comment out #define USE_UART_DMA to only engage UART in interrupt mode!
#define USE_UART_DMA

 

One you turn audio on via terminal command aud on you are on your way to play around with various instruments to feed audio into the line intput port and feed the output port to a scope, or head phones...

while the aud on or filt on is immediately typed at the PUTTY terminal console, you should see something on your scope that looks similar to either an audio signal passed in or perhaps an oscillator pulse from RackAFX.

If you engage UweS cross-over FIR filters, it can be done with filt on / filt off

I hope you found this tutorial useful. Let me know how it works out for you. As always I have attached the source code for it. If you can improve it and make it better also let me know how! I will evolve the terminal so that filter coefficients can be passed in automatically from a graphic environment. More on this later...

Cheers, 

Mario G.

Firmware Engineer

dreamsmatrix@gmail.com

Audio_Filter_Control.rar
  • Thanks for sharing your thoughts here

    Best Regards,

    Jithul

  • Sure thing! I enjoy writing these tutorials for learning purposes...Cheers, Mario

  • Hi, Mario.

     Is there anything useful for me to start programming an equalizer, which is based on the IIR filter, on the BF706 platform. I found a book named "embedded signal processing with the micro signal architecture", and I can't get access to the tutorial for IIR graphic filter. So sad!  

    Best Regards,

    Garven

  • Why is it sad ? I found the exercises in a zip file on the author's page...You will have to do the porting yourself and I clearly show you how in my console examples...Sounds like a case of someone that is not willing to try and expand a little time and effort and wishes for everything to be handed to them ready to go. That book is clearly worth its weight in gold, but you have to expand a bit of effort to figure out how to port from the BF537 or BF533 platforms which I clearly have done for you in all of my port examples. I have already ported for you some of the harder stuff to deal with such as the buttons which don't exist on the BF706-EZMINI. The DMA for the SPORT has already been dealt with in prior examples from @PatrickG, @UweS and myself. I actually went one step further and bought the BF537-EZMINI so that I can work with the book in its native format. Almost all of the examples import into Cross-Core Embedded Studio from their native Visual DSP++ format. I have gone through a solid two dozen examples and had no issues for the most part running inside the modern coding environment from ADI. Let me know if you need more suggestions. If you are asking me to port it, it might take me a little while to do it, but I'll gladly help, but it might take a week, since I've been sick for a bit. 

    Mario G.

  • Here is the author's zip files in case you cannot find them! The book is very old, so some things will be hard to get going such as the labview examples so look at them and take it with a grain of salt. The real way to learn DSP is by coding it on the Blackfin directly, not monkeying around with graphics means. It would have been nice if the labview environment on 8.5 with Blackfin worked but alas it either has been crippled with no explanation on how to get it to work and I have been unsuccessful getting the BF537-EZMINI board to run with success without struggling with that environment. The book is excellent, but you must go through it chapter by chapter and it is a handful even for those who know what they are doing! Still the best book out on the topic, very complete and incremental in hardship...Here is the zip archive in case you are looking for it!

    Mario

  • I hope you'll get well soon.

    When I read the initialization of SPROT yesterday, I couldn't find the pages 26-59, 26-67, 26-75 and 26-76 in the ADSP-BF70x Blackfin+ Processor Hardware Reference manual[1], which was mentioned by PatrickG in the Simple audio in-out code.

    // Function sport_configure initialises the SPORT0. Refer to pages 26-59, 26-67, 2

    // 26-75 and 26-76 of the ADSP-BF70x Blackfin+ Processor Hardware Reference manual.

    sport_configure:

    R0=0x3F0(X); [REG_PORTC_FER]=R0; // Set up Port C in peripheral mode

    R0=0x3F0(X); [REG_PORTC_FER_SET]=R0; // Set up Port C in peripheral mode

    R0=0x2001973; [REG_SPORT0_CTL_A]=R0; // Set up SPORT0 (A) as TX to codec, 24 bits

    R0=0x0400001; [REG_SPORT0_DIV_A]=R0; // 64 bits per frame, clock divisor of 1

    R0=0x1973(X); [REG_SPORT0_CTL_B]=R0; // Set up SPORT0 (B) as RX frm codec, 24 bits

    R0=0x0400001; [REG_SPORT0_DIV_B]=R0; // 64 bits per frame, clock divisor of 1 rts; sport_configure.end:

    or

    void sport_configure()

    {

    *pREG_SPORT0_CTL_A=0x2001973; // Set up SPORT0 (A) as TX to codec, 24 bits *pREG_SPORT0_DIV_A=0x400001; // 64 bits per frame, clock divisor of 1

    *pREG_SPORT0_CTL_B=0x0001973; // Set up SPORT0 (B) as RX from codec, 24 bits *pREG_SPORT0_DIV_B=0x400001; // 64 bits per frame, clock divisor of 1

    }

    [1]http://www.analog.com/media/en/dspdocumentation/processormanuals/BF70x_BlackfinProcessorHardwareReference.pdf

  • The reason you don't understand is because you are not using a logical method to understand the function of the registers and I cannot blame you for that! You have to have banged your head for years doing work with cryptic DSP registers to have a grasp about how to solve it! The reason those guys know is because they work in assembly and low level C using what they call register pointer casting. What page it is on is irrelevant. You will quickly realize that there are helpful flags inside the document you mention and that what matters. If the flag is on it is an one at that position, otherwise it is zero. You start to move your way up the register concatenating or flags moving up the register to the left using powers of two counting up from LSB position. Sometimes the powers of two have to be added a one two for the next position if the register position is set to a one (1). so thus become odd. ie. 1,3,5,7. A better way to visualize that I use often is to engage the calculator in windows in Programming mode! That makes it even easier...

    For example, taking Patrick's example above I can see that the register pointer 

    *pREG_SPORT0_CTL_A=0x2001973;

    that breaks out into the binary sequence above shown on my binary sequence of the calculator..

    If you were paying attention you could have easily have right clicked that register which is supported inside another header file and jumped straight to the register definition file and gotten something like this :

     

    /* =========================================================================
    SPORT0
    ========================================================================= */
    #define pREG_SPORT0_CTL_A ((volatile uint32_t *)REG_SPORT0_CTL_A) /* SPORT0 Half SPORT 'A' Control Register */
    #define pREG_SPORT0_DIV_A ((volatile uint32_t *)REG_SPORT0_DIV_A) /* SPORT0 Half SPORT 'A' Divisor Register */
    #define pREG_SPORT0_MCTL_A ((volatile uint32_t *)REG_SPORT0_MCTL_A) /* SPORT0 Half SPORT 'A' Multi-channel Control Register */
    #define pREG_SPORT0_CS0_A ((volatile uint32_t *)REG_SPORT0_CS0_A) /* SPORT0 Half SPORT 'A' Multi-channel 0-31 Select Register */
    #define pREG_SPORT0_CS1_A ((volatile uint32_t *)REG_SPORT0_CS1_A) /* SPORT0 Half SPORT 'A' Multi-channel 32-63 Select Register */
    #define pREG_SPORT0_CS2_A ((volatile uint32_t *)REG_SPORT0_CS2_A) /* SPORT0 Half SPORT 'A' Multi-channel 64-95 Select Register */
    #define pREG_SPORT0_CS3_A ((volatile uint32_t *)REG_SPORT0_CS3_A) /* SPORT0 Half SPORT 'A' Multi-channel 96-127 Select Register */
    #define pREG_SPORT0_ERR_A ((volatile uint32_t *)REG_SPORT0_ERR_A) /* SPORT0 Half SPORT 'A' Error Register */
    #define pREG_SPORT0_MSTAT_A ((volatile uint32_t *)REG_SPORT0_MSTAT_A) /* SPORT0 Half SPORT 'A' Multi-channel Status Register */
    #define pREG_SPORT0_CTL2_A ((volatile uint32_t *)REG_SPORT0_CTL2_A) /* SPORT0 Half SPORT 'A' Control 2 Register */
    #define pREG_SPORT0_TXPRI_A ((volatile uint32_t *)REG_SPORT0_TXPRI_A) /* SPORT0 Half SPORT 'A' Tx Buffer (Primary) Register */
    #define pREG_SPORT0_RXPRI_A ((volatile uint32_t *)REG_SPORT0_RXPRI_A) /* SPORT0 Half SPORT 'A' Rx Buffer (Primary) Register */
    #define pREG_SPORT0_TXSEC_A ((volatile uint32_t *)REG_SPORT0_TXSEC_A) /* SPORT0 Half SPORT 'A' Tx Buffer (Secondary) Register */
    #define pREG_SPORT0_RXSEC_A ((volatile uint32_t *)REG_SPORT0_RXSEC_A) /* SPORT0 Half SPORT 'A' Rx Buffer (Secondary) Register */
    #define pREG_SPORT0_CTL_B ((volatile uint32_t *)REG_SPORT0_CTL_B) /* SPORT0 Half SPORT 'B' Control Register */
    #define pREG_SPORT0_DIV_B ((volatile uint32_t *)REG_SPORT0_DIV_B) /* SPORT0 Half SPORT 'B' Divisor Register */
    #define pREG_SPORT0_MCTL_B ((volatile uint32_t *)REG_SPORT0_MCTL_B) /* SPORT0 Half SPORT 'B' Multi-channel Control Register */
    #define pREG_SPORT0_CS0_B ((volatile uint32_t *)REG_SPORT0_CS0_B) /* SPORT0 Half SPORT 'B' Multi-channel 0-31 Select Register */
    #define pREG_SPORT0_CS1_B ((volatile uint32_t *)REG_SPORT0_CS1_B) /* SPORT0 Half SPORT 'B' Multi-channel 32-63 Select Register */
    #define pREG_SPORT0_CS2_B ((volatile uint32_t *)REG_SPORT0_CS2_B) /* SPORT0 Half SPORT 'B' Multichannel 64-95 Select Register */
    #define pREG_SPORT0_CS3_B ((volatile uint32_t *)REG_SPORT0_CS3_B) /* SPORT0 Half SPORT 'B' Multichannel 96-127 Select Register */
    #define pREG_SPORT0_ERR_B ((volatile uint32_t *)REG_SPORT0_ERR_B) /* SPORT0 Half SPORT 'B' Error Register */
    #define pREG_SPORT0_MSTAT_B ((volatile uint32_t *)REG_SPORT0_MSTAT_B) /* SPORT0 Half SPORT 'B' Multi-channel Status Register */
    #define pREG_SPORT0_CTL2_B ((volatile uint32_t *)REG_SPORT0_CTL2_B) /* SPORT0 Half SPORT 'B' Control 2 Register */
    #define pREG_SPORT0_TXPRI_B ((volatile uint32_t *)REG_SPORT0_TXPRI_B) /* SPORT0 Half SPORT 'B' Tx Buffer (Primary) Register */
    #define pREG_SPORT0_RXPRI_B ((volatile uint32_t *)REG_SPORT0_RXPRI_B) /* SPORT0 Half SPORT 'B' Rx Buffer (Primary) Register */
    #define pREG_SPORT0_TXSEC_B ((volatile uint32_t *)REG_SPORT0_TXSEC_B) /* SPORT0 Half SPORT 'B' Tx Buffer (Secondary) Register */
    #define pREG_SPORT0_RXSEC_B ((volatile uint32_t *)REG_SPORT0_RXSEC_B) /* SPORT0 Half SPORT 'B' Rx Buffer (Secondary) Register */

    All of those register definitions are covered in detail inside the book you mentioned above. Blackfins are wonderfully similar, even if slightly different architecture wise...

    // Function configure_sport initializes the SPORT0. Refer to pages 31-55, 31-63,
    // 31-72 and 31-73 of the ADSP-BF70x Blackfin+ Processor Hardware Reference, Revision 1.0.
    void configure_SPORT()
    {
    *pREG_SPORT0_CTL_A = 0x02011972; // Set up SPORT0 (A) as TX to CODEC, I2S, 24 bits
    *pREG_SPORT0_DIV_A = 0x00400001; // 64 bits per frame, clock divisor of 1
    *pREG_SPORT0_CTL_B = 0x00011972; // Set up SPORT0 (B) as RX from CODEC, I2S, 24 bits
    *pREG_SPORT0_DIV_B = 0x00400001; // 64 bits per frame, clock divisor of 1
    }

    Look up the register definition inside the document you mentioned by simply invoking the search bar of the .PDF and type sport

    Lets go ahead and choose the one in question that you highlighted and lets click on it inside the .PDF

    Now those bit positions I have shown you on the calculator should become painfully obvious...They should map correctly into the refference doc as you see in the breakout diagram. I'm not going to get into the details for you, I'm only showing you the road map on how to decipher this stuff. What is left for you to do is pay attention to the book, because it gives detailed insight about how this SPORT perhipheral(s) and codec(s) work. It might take a few days of probing around to get it! What would be even more fun for you to do is to actually use that number shown above and interpret it as a collection of flags or(ed) together as shown by the professor inside the book! 

    HINT - Those are found inside the def files for the corresponding blackfin. Searching of some headers should get you there! For example right clicking on one particular flag name in the source code for the BF537 jumped to this def file...Doing a search in the PDF for that flag by scrolling down the peripheral page, I can get great detail as far as what that particular flag means...

    *pDMA3_CONFIG = WNR | WDSIZE_32 | DI_EN | FLOW_1 | DMA2D | DI_SEL;

    As you can see, doing your own investigation of those flags is way superior method of understanding rather than deciphering scribble that could have originated from an older document which you have no idea what it was and which version. I'm showing you how to drill down and find stuff faster and more accurately! The header files are your friend...

    Of course you can always take it by faith that those guys knew what they were doing when they set them up, but that won't help you understand! 

    You can find all the flag definitions for registers inside defBF706.h

    You don't even need a manual most of the time, but hey, it is good read! Happy digging...

    Mario

  • I think "Thank you" is so weak to express my feeling of gratitude. The answer from you is so comprehensive and helpful for me to understand the configuration. It's time for Happy DSPing the IIR equalizer.  I will try my best to reach the destination, although there might be some obstacles on the road.

  • You're welcome and I'm glad it helped you reach your goal...That book has excellent practical examples that are super easy to port to the BF707! Cheers. Mario