Using BUFG to drive clock loads - buffer

I'm attempting to work with pixel data that is output to a DVI chip. A variety of clock frequencies are used because the DVI chip registers are programmed using I2C (therefore needs a clock < 500 KHz) - from a clock divider.
The DVI chip needs a 40 MHz differential pixel clock, however, the DVI takes displays half a byte twice a cycle, so a further 80 MHz clock is needed to push each half of the pixel onto the data lines with each half cycle, these are from a DCM.
This has led to a variety of problems. I attempted to just use the double pixel clock rate to swap each half of the pixel, however I got the error:
This design contains a global buffer instance, <out2_bufg>,
driving the net, <pxlclk_p_int>, that is driving the following (first 30)
non-clock load pins.
So I added a BUFG element between the output of the DCM and the components using the signal - but it hasn't changed anything, instead the error is now thrown twice on both the input and output of the BUFG.
How can I fix this - given I've just added a BUFG and it doesn't like it!
My code is below; I've tried to cut out the unrelated things that aren't related to the clock but its still quite long!
EDIT 1: I have added the block, which when added to the system, caused the error (that wasn't there before) Its in the second block of code! I am currently working on the other suggestions RE the differential signalling, and will edit again when done!
Thanks very much,
David
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
library UNISIM;
use UNISIM.VComponents.all;
ENTITY I2CBus IS
PORT(
SYSCLK_N : IN STD_LOGIC; --system 200MHz differential clock
SYSCLK_P : IN STD_LOGIC;
BTN : IN STD_LOGIC; -- to manually change reset
LED : OUT STD_LOGIC_VECTOR(3 downto 0); --to observe reset value
SCL_DBG : OUT STD_LOGIC; -- copy of SCL to output pin
SDA_DBG : OUT STD_LOGIC; --copy of SDA to output pin
SCL : OUT STD_LOGIC; --Serial Clock Line
SDA : INOUT STD_LOGIC; --Serial Data Line
DVIRESET_N : OUT STD_LOGIC; --reset_n to dvi device
DVI_ENABLE : OUT STD_LOGIC; --enable DVI device inputs (active high)
PXLCLK_P : OUT STD_LOGIC; --pixel clock differential pair through buffers
PXLCLK_N : OUT STD_LOGIC;
DVI_DATA : OUT STD_LOGIC_VECTOR(11 downto 0); --12 bit multiplexed pixel to DVI
HSYNC : OUT STD_LOGIC; --Horizontal/Vertical sync timing pulses
VSYNC : OUT STD_LOGIC
);
END I2CBus;
ARCHITECTURE behavior OF I2CBus IS
COMPONENT IIC_MASTER --sends data to write out onto SDA bus line in I2C protocol
PORT(SCL : IN STD_LOGIC;
SCL2X : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
ENA : IN STD_LOGIC;
ADR : IN STD_LOGIC_VECTOR(6 DOWNTO 0);
REG : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
RW : IN STD_LOGIC;
DAT_WR : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
BUSY : OUT STD_LOGIC;
SDA : INOUT STD_LOGIC;
ACK_ERR : BUFFER STD_LOGIC);
END COMPONENT IIC_MASTER;
COMPONENT DCM --takes input system differential clocks, generates further clocks
PORT(
SYSCLK_P : IN STD_LOGIC; -- CLOCK IN PORTS 200MHZ DIFFERENTIAL
SYSCLK_N : IN STD_LOGIC;
-- CLOCK OUT PORTS
SYSCLK : OUT STD_LOGIC;
PXLCLK : OUT STD_LOGIC;
PXLCLK2X : OUT STD_LOGIC
);
END COMPONENT;
COMPONENT CLK_DIVIDER --divides system clock down for i2c bus clock line
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
RESET_N_OUT : OUT STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END COMPONENT CLK_DIVIDER;
COMPONENT DVI_INITIALISE --initialises CH7301c registers to necessary operation values
PORT(SYSCLK : IN STD_LOGIC;
ACK_ERR : IN STD_LOGIC;
BUSY : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
COUNT : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
DVI_WR : OUT STD_LOGIC := '0';
DVI_REGDATA : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
DVI_WDATA : OUT STD_LOGIC_VECTOR(7 DOWNTO 0));
END COMPONENT DVI_INITIALISE;
COMPONENT DVI_INTERFACE --outputs sync pulses, controls enable and manages pixel addresses
PORT(PIXEL_CLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
PXL_ADDR : OUT STD_LOGIC_VECTOR(19 DOWNTO 0) := (OTHERS => '0');
HSYNC, VSYNC : OUT STD_LOGIC := '1';
ENABLE : OUT STD_LOGIC := '0');
END COMPONENT DVI_INTERFACE;
COMPONENT DVI_MUX
PORT(PXLCLK : IN STD_LOGIC;
PXLCLK2X : IN STD_LOGIC;
PXL_DAT : IN STD_LOGIC_VECTOR(23 DOWNTO 0); --pixel as RGB
DATA : OUT STD_LOGIC_VECTOR(11 DOWNTO 0); --multiplexed output
RESET_N : IN STD_LOGIC); --reset low signal
END COMPONENT DVI_MUX;
--Inputs
signal reset_n_input : std_logic; -- input reset from button
----Outputs ------
signal sda_internal : STD_LOGIC; -- Internal SDA
----Clocks-----
signal SCL_internal : std_logic; -- i2c clock
signal SCL2X_internal : std_logic; -- i2c x2 to load SDA data
signal sysclk : std_logic; --system clock
signal pxlclk_p_int : std_logic; --differential pixel clock pair
signal pxlclk_n_int : std_logic;
signal pxlclk : std_logic; --pxlclk after BUFG
signal pxlclk2x_int : STD_LOGIC; --2x pixel clock for loading pixel data
-----Internal Control Signals ---
signal reset_n : std_logic; --active high
signal busy : std_logic; --low when not i2c not busy
signal ack_err : std_logic; --high when i2c ackknowledge error occurs
----Internal Data-----
signal i2c_reg : STD_LOGIC_VECTOR(7 DOWNTO 0); --register data for I2C
signal i2c_rw : STD_LOGIC; --R/W* for I2C
signal i2c_data : STD_LOGIC_VECTOR(7 DOWNTO 0); --Data for I2C
BEGIN
master : IIC_Master
port map(
SCL => SCL_internal,
SCL2X => SCL2X_internal,
RESET_N => RESET_N,
ENA => '1',
ADR => "1110110",
REG => i2c_reg,
RW => i2c_rw,
DAT_WR => i2c_data,
BUSY => busy,
SDA => sda_internal,
ACK_ERR => ack_err
);
DCM_SYS : DCM
port map(
SYSCLK_P => SYSCLK_P, --take differential input clock
SYSCLK_N => SYSCLK_N,
SYSCLK => sysclk, --200 MHz system clock
PXLCLK => pxlclk, --and pixel clock
PXLCLK2X => pxlclk2x_int --pixel clock at double rate
);
Clk_Div : Clk_Divider
generic map(
INPUT_FREQ => 200000000, --200 MHz system input
OUT1_FREQ => 100000, --to work correctly, 200 must go into all frequencies (x2).
OUT2_FREQ => 200000 --i.e. from 200, cannot generate 40 as 200/40/2 = 2.5, which will be 2
)
port map(
SYSCLK => sysclk,
RESET_N => reset_n_input,
RESET_N_OUT => reset_n,
OUT1 => scl_internal,
OUT2 => scl2x_internal
);
data_load : component DVI_INITIALISE
port map(
SYSCLK => sysclk,
ACK_ERR => ack_err,
BUSY => busy,
RESET_N => reset_n,
COUNT => LED,
DVI_WR => i2c_rw,
DVI_REGDATA => i2c_reg,
DVI_WDATA => i2c_data
);
interface : DVI_INTERFACE
port map(
PIXEL_CLK => pxlclk_p_int,
RESET_N => reset_n,
PXL_ADDR => open,
HSYNC => HSYNC,
VSYNC => VSYNC,
ENABLE => DVI_ENABLE
);
pxl_mux : DVI_MUX
port map(
PXLCLK => pxlclk_p_int,
PXLCLK2X => pxlclk2x_int,
PXL_DAT => x"FF0000",
DATA => DVI_DATA,
RESET_N => reset_n
);
------------OUTPUT BUFFERS (CLOCK FORWARDING)------------
ODDR_pxlclk_p : ODDR2
generic map(
DDR_ALIGNMENT => "NONE",
INIT => '0',
SRTYPE => "SYNC")
port map(
Q => PXLCLK_P, --output to positive output
C0 => pxlclk_p_int, --differential input
C1 => pxlclk_n_int,
CE => '1', --chip enable tied high
D0 => '1',
D1 => '0',
R => '0',
S => '0'
);
ODDR_pxlclk_n : ODDR2
generic map(
DDR_ALIGNMENT => "NONE",
INIT => '0',
SRTYPE => "SYNC")
port map(
Q => PXLCLK_N, --output to negative output
C0 => pxlclk_n_int,
C1 => pxlclk_p_int,
CE => '1',
D0 => '1',
D1 => '0',
R => '0',
S => '0'
);
out2_bufg : BUFG port map(I => pxlclk, O => pxlclk_p_int); --ERROR THROWN ON I/O HERE
----------------Mappings---------------------------
reset_n_input <= not BTN; --when button pressed, reset
SCL <= 'Z' when scl_internal = '1' else scl_internal;
SCL_DBG <= 'Z' when scl_internal = '1' else scl_internal;
SDA <= sda_internal;
SDA_DBG <= SDA; --copy SDA to debug line
DVIRESET_N <= reset_n; --reset DVI device
pxlclk_n_int <= not pxlclk_p_int; --create differential pair
end behavior;
DVI_MUX When I added this block to the system, the error was thrown where it previously wasnt
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY DVI_MUX IS
PORT(
PXLCLK : IN STD_LOGIC; --pixel clock
PXLCLK2X : IN STD_LOGIC; --double freq. pixel clock
PXL_DAT : IN STD_LOGIC_VECTOR(23 downto 0); --pixel in RGB format
DATA : OUT STD_LOGIC_VECTOR(11 downto 0); --
RESET_N : IN STD_LOGIC
);
END ENTITY DVI_MUX;
architecture RTL of DVI_Mux is
begin
mux_proc : process(PXLCLK2X)
begin
if falling_edge(PXLCLK2X) then
if PXLCLK = '0' then -- if pxlclk low, load first half of pixel
DATA <= PXL_DAT(23 downto 16) & PXL_DAT(11 downto 8);
else --else load second half
DATA <= PXL_DAT(15 downto 12) & PXL_DAT(7 downto 0);
end if;
if RESET_N = '0' then --if reset active7
DATA <= (others => '1');
end if;
end if;
end process;
end architecture RTL;

This doesn't directly answer your question, but it looks like you're trying to use a DDR output primitive to drive an external differential clock pin. This is a good thing to do, but the way you have done it seems unconventional. The standard way to do this would look more like this:
EDIT: I've realised that I misunderstood the question, and have incorporated the differential output instantiation from #StuartVivian
pxclk_inverted <= not pxlclk;
ODDR_pxlclk_p : ODDR2
generic map(
DDR_ALIGNMENT => "NONE",
INIT => '0',
SRTYPE => "SYNC")
port map(
Q => PXLCLK_OUT,
C0 => pxlclk,
C1 => pxclk_inverted,
CE => '1',
D0 => '1',
D1 => '0',
R => '0',
S => '0'
);
inst_obufds : OBUFDS
generic map (
IOSTANDARD=>"LVDS_25"
)
port map
(
O => PXLCLK_OUT_P,
OB => PXLCLK_OUT_N,
I => PXLCLK_OUT
);
In IO assignment, PXLCLK_OUT_N/P will then be set to use a differential IO standard. In a graphical pin assignment window, this port will then use two pins, and will only allow you to assign them to a valid positive/negative pair. What you're trying to do is manually create the positive and negative signals before the DDR output primitive, which is not the way it's supposed to work.
I think if you use this technique, and get rid of your BUFG, your problem should go away. If not, maybe update the question with this, and whatever the new problem might be.
Now that you've updated the question, I can see that your pixel output data also seems to be a DDR bus. You are trying to infer a DDR output behavior by implementing a multiplexer using a clock signal as the select line.
The more standard way to do this would be to instantiate n DDR output primitives, one for each bit of the parallel DDR output. According to the latest VHDL standard (VHDL2008) it is possible to infer a DDR output, but the problem with this is that this technique does not yet have widespread toolchain support.

After that error message there would have been a list of up to 30 pins in the design that the tool believes you are driving with the clock but are not actual clock pins.
The C0 and C1 pins should be treated as clocks, so I doubt it's complaining about those. As the clock signal goes to other blocks which we haven't got the code for, could these contain end points for the clock that aren't clock pins?
I agree with scary_jeff's answer regarding the use of the ODDR2. To make a differential output from the output of the ODDR you need to instantiate a differential driver in the code i.e. LVDS_25 or LVDS in Xilinx architecture, and then set the logic standard in the ucf or xdc/sdc constraints files. The tools documentation should give clear examples of this.
inst_obufds : OBUFDS
generic map ( IOSTANDARD=>"LVDS_25" )
port map
( O => DIFF_P,
OB => DIFF_N,
I => internal_signal
);

The message is reported because pxlclk is used to drive the multiplexer in the component of DVI_MUX and this multiplexer is placed before the flipflop. To reach the select signal of the multiplexer, the signal pxlclk must use the general purpose routing instead of the dedicated clock tree. Please read UG381 from Xilinx, pp. 61/62 on how the Spartan-6 supports DDR outputs.
I recommentd to use the ODDR2 component also for the data pins. The inputs D0 and D1 just provide the data which should be output with the rising edge of clock C0 and C1 respectivly. Please lookup the UG615 from Xilinx for a thruth table and more information.
If the documentation seems to be unclear, I recommend to simulate the component DVI_MUX standalone first.

Related

how to calculate the CAN bus baud rate from the Tq and clock frequency ?

first , I think I know how to calculate the CAN bus Baud rate form the parameter in picture blew ,this is a CAN FD config.
clock frequency :80000 k
pre-scaler :1
so we can get the Tq = 1/80000 K
BTL cycles : 40
time for a bit = 40 * (1/80000K) = 1/2000k
So we can get the baud rate = 1/ (1/2000k) = **2000k .**
this Baud rate which we calculated is equal to the value which the CANoe Generated.
But what puzzles me is :when I use this method to calculate the Baud Rate for a CAN(not CAN FD),the result is different from the value which the CANoe generated ,why ??? is there something different between CAN and CAN FD ??
could you please to help me ? thank you very much !
clock :16000K
Pre-sacler :1
tq = 1/16000k
BTL : 16
time for a bit = 16*1/16000k = 1/1000k
baud rate = 1000k
but result generate via CANoe is 500k ,seems somewhere i missing a "divide by 2 " ??
the CAN control chip for CANOE is SJA1000 ,from the CANOE help document.
for this chip :
CAN clock = system clock * pre-scaler * 2
the key-point of this question is the "2" here ,for other chip ,such as STM32F103 ,Clock set for CAN bus is 36Mhz,it doesnt need to divide by “2”
so the clock frequency below maybe the system clock I guess
According to this rule, I set the parameters of another development board, and the measured communication was successful.
meanwhile the user of CANOE should just focus on Baud rate and sample point ,There is no need to pay too much attention to other parameters.
Hope this helps you

Add low frequency amplitude modulation to noise

I am trying to reproduce a SoX script using ChucK which creates brown noise with a slight oscillation (tremolo).
The SoX script is:
set -u
set -e
minutes=${1:-'59'}
repeats=$(( minutes - 1 ))
center=${2:-'1786'}
wave=${3:-'0.0333333'}
noise='brown'
len='01:00'
if [ $minutes -eq 1 ] ; then
progress='--show-progress'
else
progress='--no-show-progress'
fi
echo " :: Please stand-by... sox will 'play' $noise noise for $minutes minute(s)."
play $progress -c 2 --null -t alsa synth $len ${noise}noise \
band -n $center 499 \
tremolo $wave 43 reverb 19 \
bass -11 treble -1 \
vol 14dB \
repeat $repeats
exit 0
The following ChucK script, modified from the wind2.ck example, creates brown noise of the desired frequency:
Noise n => BiQuad f => dac;
0.99 => f.prad;
0.0333333 => f.gain;
1 => f.eqzs;
0.00 => float t;
while(true)
5::ms => now;
I am unable to reproduce the effect that the SoX tremolo option creates.
It seems like I should be able to add a Sine wave to the main chain and then oscillate that parameter. I am trying variations of FM.ck frequency modulation example without success:
SinOsc m => Noise n => BiQuad f => dac;
20 => m.freq;
200 => m.gain;
0.99 => f.prad;
0.0333333 => f.gain;
1 => f.eqzs;
0.00 => float t;
while(true)
30 + ( Math.sin(t) + 1.0 ) * 10000.0 => m.sfreq;
t + .004 => t;
5::ms => now;
I expect to hear some fluctuation in the tone, but instead, no sound appears to be produced.
How can I add a low frequency amplitude modulation to the brown noise I've generated?

sliding window in verilog when doing convolution

I am working on my CNN project in Verilog , but I am having some problems of implementing convolution procedure of Image with 3x3 Filter. I wrote a code for convolutional module, but now when it comes to convolution, I have to read the values from memory, which contains the pixels of the image. The thing is that I have to read these values in particular order, since convolution takes the dot product of 2 matrices and then strides it by 1 to the right. So let's say if the image is 5x5 matrix which stored in a memory array
[ a1 a2 a3 a4 a5
a6 a7 a8 a9 a10
a11 a12 a13 a14 a15 ] - memory Ram
how can I read the values of the memory in the following order:
a1 then a2 then a3 , then a6 then a7 then a8, and last row a11 a12 a13, and then stride and start over starting with a2 , a3, etc. til I reach the end of my array. Please suggest any solution how I should address the memory in this situation, the code snippet would be highly appreciated. Thank you.
p.s. my memory array will contain a lot of data, approximately will be a matrix of [400x300] , where the filter is [3x3].
Looks like a simple case of nested for-loops. This walk through the 16-entry memory as you wanted:
for (start=0; start<3; start=start+1)
for(i=1; i<16; i=i+5)
for (j=0; j<3; j=j+1)
data = mem[start+i+j]; // C: printf("%d\n",start+i+j);
Note that the code is both C and Verilog compatible so you can test your sequence in a C-compiler if you want (I did).
If you don't like the for loops you can make them into counters. In HDL you always reverse the order and start with the inner loop:
if (j<3)
j <= j + 1;
else
begin
j <=0;
if (i<16) // should be 15 if you start from 0
i <= i + 5;
else
begin
i <= 1; // You sure it should not be zero?
if (start<3)
start <= start + 1;
else
begin
start <= 0;
all_done <= 1'b1
end // nd of start
end // end of j
end // end of i
In a different part pf the design you can now use start+i+j as address.
Last : I would start with indices 0,1,2 as your picture is likely to start from memory address 0. You need to change the 'i' loop for that.
(HDL code is not compiled or tested)

Image Processing Pipelining in VHDL

I am currently trying to develop a Sobel filter in VHDL. I am using a 640x480 picture that is stored in a BRAM. The algorithm uses a 3x3 matrix of pixels of the image for processing each output pixel. My problem is that I currently only know of putting an image into a BRAM where each address of the BRAM holds one pixel value. This means I can only read one pixel per clock. My problem is that I am trying to pipeline the data so I would ideally need to be able to get three pixel values (one from each row of the picture) per clock so after my initial latency, I can load in three new pixel values per clock and get an output pixel on every clock. I am looking for a way to do this but cannot figure it out.
The only way I can think of to fix this is to have the image in 3 BRAMs. that way I can read in values from 3 rows per each clock cycle. However, there is not enough memory space to fit even one more RAM large enough to fit a 640x480 image let alone three. I could lower the picture size to do it this way, but I really want to do it with my current 640x480 image size.
Any help or guidance would be greatly appreciated.
A simple solution would be to store 1/4th of the image in 4 separate memories. First memory contain every 4th line, second every 4th line, starting from second line, etc. I would use 4 even if you need 3 lines, since 4 evenly divides 480 and every other standard resolution. Also, finding a binary number modulo 4 is trivial, which is needed to order the memories.
You can use the MSB of the line number to address your RAM, and the LSBs to figure out the relative order of each RAM output (code is only to demonstrate idea, it's not usable as is...):
address <= line(line'left downto 2) & col; -- Or something more efficent on packing
data0 <= ram0(address);
data1 <= ram1(address);
data2 <= ram2(address);
data3 <= ram3(address);
case line(1 downto 0) is
when "00" =>
line0 <= data0;
line1 <= data1;
line2 <= data2;
when "01" =>
line0 <= data1;
line1 <= data2;
line2 <= data3;
when "10" =>
line0 <= data2;
line1 <= data3;
line2 <= data0;
when "11" =>
line0 <= data3;
line1 <= data0;
line2 <= data1;
when others => null;
end case;
I made a sobel filter few years ago. To do that, i wrote a pipeline that gives 9 pixels at each clock cycle:
architecture rtl of matrix_3x3_builder_8b is
type fifo_t is array (0 to 2*IM_WIDTH + 2) of std_logic_vector(7 downto 0);
signal fifo_int : fifo_t;
begin
p0_build_5x5: process(rst_i,clk_i)
begin
if( rst_i = '1' )then
fifo_int <= (others => (others => '0'));
elsif( rising_edge(clk_i) )then
if(data_valid_i = '1')then
for i in 1 to 2*IM_WIDTH + 2 loop
fifo_int(i) <= fifo_int(i-1);
end loop;
fifo_int(0) <= data_i;
end if;
end if;
end process p0_build_5x5;
data_o1 <= fifo_int(0*IM_WIDTH + 0);
data_o2 <= fifo_int(0*IM_WIDTH + 1);
data_o3 <= fifo_int(0*IM_WIDTH + 2);
data_o4 <= fifo_int(1*IM_WIDTH + 0);
data_o5 <= fifo_int(1*IM_WIDTH + 1);
data_o6 <= fifo_int(1*IM_WIDTH + 2);
data_o7 <= fifo_int(2*IM_WIDTH + 0);
data_o8 <= fifo_int(2*IM_WIDTH + 1);
data_o9 <= fifo_int(2*IM_WIDTH + 2);
end rtl;
Here you read the image pixel by pixel to build your 3x3 matrix. The pipeline is longer to fill up but once completed, you have a new matrix each clock pulse.
If you want to continue storing the whole image, then I would do as Jonathan Drolet recommended and cycle between four rams while writing and read all 4 at once (muxing the three you care about into 3 registers).
This works because your rams will be deep enough that you will still be able to get full BRAM utilization at 1/4 the depth (77k deep still) and your reads can be predictably segmented.
For the specifics of this problem, Nicolas Roudel's method is much cheaper with BRAM, although you can't store the whole image at one time, so wherever you send your results can't backpressure you unless you can backpressure your data source. That may or may not matter for your application.
When you try to do something like this with extremely wide, but fairly shallow (1k deep) rams segmenting will use more block ram (or even start inferring distributed ram). When the reads do not follow a particular pattern (the pattern in your case is that they are all sequential and adjacent locations), the ram cannot be segmented. The best strategy to maintain efficient BRAM use is often to build quad port rams from the natively dual port block rams by clocking them with a 2x clock that is phase aligned with your normal clock, allowing you to do a write and 3 reads every 1x clock cycle.

Detecting a low frequency tone in an audio file

I know this question been asked hundred times... But I am getting frustrated with my result so I wanted to ask again. Before I dive deep into fft, I need to figure this simple task out.
I need to detect a 20 hz tone in an audiofile. I insert the 20hz tone myself like in the picture. (It can be any frequency as long as listener can't hear it so I thought I should choose a frequency around 20hz to 50 hz)
info about the audiofile.
afinfo 1.m4a
File: 1.m4a
File type ID: adts
Num Tracks: 1
----
Data format: 1 ch, 22050 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Mono
estimated duration: 8.634043 sec
audio bytes: 42416
audio packets: 219
bit rate: 33364 bits per second
packet size upper bound: 768
maximum packet size: 319
audio data file offset: 0
optimized
format list:
[ 0] format: 1 ch, 22050 Hz, 'aac ' (0x00000000) 0 bits/channel, 0 bytes/packet, 1024 frames/packet, 0 bytes/frame
Channel layout: Mono
----
I followed this three tutorials and I came up with a working code that reads audio buffer and gives me fft doubles.
http://blog.bjornroche.com/2012/07/frequency-detection-using-fft-aka-pitch.html
https://github.com/alexbw/iPhoneFFT
How do I obtain the frequencies of each value in an FFT?
I read the data as follows
// If there's more packets, read them
inCompleteAQBuffer->mAudioDataByteSize = numBytes;
CheckError(AudioQueueEnqueueBuffer(inAQ,
inCompleteAQBuffer,
(sound->packetDescs?nPackets:0),
sound->packetDescs),
"couldn't enqueue buffer");
sound->packetPosition += nPackets;
int numFrequencies=2048;
int kNumFFTWindows=10;
SInt16 *testBuffer = (SInt16*)inCompleteAQBuffer->mAudioData; //Read data from buffer...!
OouraFFT *myFFT = [[OouraFFT alloc] initForSignalsOfLength:numFrequencies*2 andNumWindows:kNumFFTWindows];
for(long i=0; i<myFFT.dataLength; i++)
{
myFFT.inputData[i] = (double)testBuffer[i];
}
[myFFT calculateWelchPeriodogramWithNewSignalSegment];
for (int i=0;i<myFFT.dataLength/2;i++) {
NSLog(#"the spectrum data %d is %f ",i,myFFT.spectrumData[i]);
}
and my out out log something like
Everything checks out for 4096 samples of data
Set up all values, about to init window type 2
the spectrum data 0 is 42449.823771
the spectrum data 1 is 39561.024361
.
.
.
.
the spectrum data 2047 is -42859933071799162597786649755206634193030992632381393031503716729604050285238471034480950745056828418192654328314899253768124076782117157451993697900895932215179138987660717342012863875797337184571512678648234639360.000000
I know I am not calculating the magnitude yet but how can I detect that sound has 20 hz in it? Do I need to learn Goertzel algorithm?
There are many ways to convey information which gets inserted into then retrieved from some preexisting wave pattern. The information going in can vary things like the amplitude (amplitude modulation) or freq (frequency modulation), etc. Do you have a strategy here ? Note that the density of information you wish to convey can be influenced by such factors as the modulating frequency (higher frequencies naturally can convey more information as it can resolve changes more times per second).
Another approach is possible if both the sender and receiver have the source audio (reference). In this case the receiver could do a diff between reference and actual received audio to resolve out the transmitted extra information. A variation on this would be to have the sender send ~~same~~ audio twice, first send the reference untouched audio followed by a modulated version of this same reference audio that way the receiver just does a diff between these two audibly ~~same~~ clips to resolve out the embedded audio.
Going back to your original question ... if the sender and receiver have an agreement ... say for some time period X the reference pure 20 Hz tone is sent followed by another period X that 20 Hz tone is modulated by your input information to either alter its amplitude or frequency ... then just repeat this pattern ... on receiving side they just do a diff between each such pair of time periods to resolve your modulated information ... for this to work the source audio cannot have any tones below some freq say 100 Hz (you remove such frequency band if needed) just to eliminate interference from source audio ... you have not mentioned what kind of data you wish to transmit ... if its voice you first would need to stretch it out in effect lowering its frequency range from the 1 kHz range down to your low 20 Hz range ... once result of diff is available on receiving side you then squeeze this curve to restore it back to normal voice range of 1kHz ... maybe more work than you have time for but this might just work ... real AM/FM radio uses modulation to send voice over mega Hz carrier frequencies so it can work

Resources