AVR – MCP4921, 自定义正弦波频率

huangapple go评论58阅读模式
英文:

AVR - MCP4921, custom sinewave frequency

问题

I'm trying to generate a sinewave of 40KHz from an avr micro-controller (atmega328p) interfaced with an MCP4921. I have an already prepared sinewave table generated online and i use the SPI protocol. Everything is working well except one slight problem. In the atmega328, i calculated the timer to generate an interrupt at 40KHz, and during each ISR call, i execute a SPI_Transmit() function. So i can come to frequency of the sinewave i want. Am stuck on how to get it right.

The SPI protocol is set to run at 8MHz because am using a 16MHz crystal and the max i can do is 8MHz.

AS far as the configuration of the timer are concerned, this is how i went about it,

#define TableSize = 256

const uint16_t sinewaveTable [TableSize] {
   0x800,0x832,0x864,0x896.... // I have 256 values in this table
}

void Setup_Timer()
{
    // Clear registers
    TCCR1A = 0;
    TCCR1B = 0;

    // CTC
    TCCR1B |= (1 << WGM12);

    // Set TOP Value (OCR1A) for 40kHz clock signal
    OCR1A = 199;

    // Prescaler 1
    TCCR1B |= (1 << CS10);

    // Output Compare Match A Interrupt Enable
    TIMSK1 |= (1 << OCIE1A);
}

And then my ISR is configured as follows

ISR(TIMER1_COMPA_vect) {
    // Chip select low
    CS_DAC_LOW();

    // concatenate command with sinewave value
    uint16_t cmd_and_value = (CMD << 12) | sinewaveTable[SineWave_TableCounter];

    // send the 
    SPI_MasterTransciever(cmd_and_value);
    SineWave_TableCounter++;

    if(SineWave_TableCounter>= TableSize) 
        SineWave_TableCounter= 0;

    CS_DAC_HIGH();
}

The only thing i think i'm sure about is that the final Timer frequency will have to be divided with the number of samples in the table to get the real frequency of the sinewave. That means that if i have lets say 40KHz and i have, then

AVR – MCP4921, 自定义正弦波频率

Again, this is far from what i am anticipating. But then, should i sample at a NyQuist frequency of atleast 80KHz, although this too would give me

AVR – MCP4921, 自定义正弦波频率

which is also still far from what i want. And thats why i am seeking any help or leads

英文:

I'm trying to generate a sinewave of 40KHz from an avr micro-controller (atmega328p) interfaced with an MCP4921. I have an already prepared sinewave table generated online and i use the SPI protocol. Everything is working well except one slight problem. In the atmega328, i calculated the timer to generate an interrupt at 40KHz, and during each ISR call, i execute a SPI_Transmit() function. So i can come to frequency of the sinewave i want. Am stuck on how to get it right.

The SPI protocol is set to run at 8MHz because am using a 16MHz crystal and the max i can do is 8MHz.

AS far as the configuration of the timer are concerned, this is how i went about it,

#define TableSize = 256

const uint16_t sinewaveTable [TableSize] {
   0x800,0x832,0x864,0x896.... // I have 256 values in this table
}

void Setup_Timer()
{
    // Clear registers
    TCCR1A = 0;
    TCCR1B = 0;

    // CTC
    TCCR1B |= (1 << WGM12);

    // Set TOP Value (OCR1A) for 40kHz clock signal
    OCR1A = 199;

    // Prescaler 1
    TCCR1B |= (1 << CS10);

    // Output Compare Match A Interrupt Enable
    TIMSK1 |= (1 << OCIE1A);
}

And then my ISR is configured as follows

ISR(TIMER1_COMPA_vect) {
    // Chip select low
    CS_DAC_LOW();

    // concatenate command with sinewave value
    uint16_t cmd_and_value = (CMD << 12) | sinewaveTable[SineWave_TableCounter];

    // send the 
    SPI_MasterTransciever(cmd_and_value);
    SineWave_TableCounter++;

    if(SineWave_TableCounter>= TableSize) 
        SineWave_TableCounter= 0;

    CS_DAC_HIGH();
}

The only thing i think i'm sure about is that the final Timer frequency will have to be divided with the number of samples in the table to get the real frequency of the sinewave. That means that if i have lets say 40KHz and i have, then

AVR – MCP4921, 自定义正弦波频率

Again, this is far from what i am anticipating. But then, should i sample at a NyQuist frequency of atleast 80KHz, although this too would give me

AVR – MCP4921, 自定义正弦波频率

which is also still far from what i want. And thats why i am seeking any help or leads

答案1

得分: 0

无法生成40kHz正弦波,同时每秒输出40,000个样本。
要生成40kHz波形,您至少需要输出80,000个样本(这是Nyquist频率的原理)。但即使如此,也无法生成纯正弦波,因为波形将由两个点来确定,没有任何中间值。

由于您的DAC需要发送16位数据(即32个CPU周期),还需要在CS上下切换(至少需要2个额外的CPU周期),您可以实现的理论最大采样频率为16 MHz / (32 + 2) = 470.6 ksamples每秒。这仅相当于输出正弦波一个周期内的11.7个样本。
要实现这一点,您需要禁用所有中断并直接写入输出寄存器,您可以使用较短的正弦表或跳过某些数值。

实际上,您可以通过跳过正弦表中的一定数量的值来实现任何输出频率。

英文:

You cannot generate a 40kHz sine wave, while sending to output 40k samples per second.
To generate 40kHz wave you need output at least 80k samples (that what Nyquist frequency is about). But even then it will not be a sine wave, because the wave will be determined by two points without any intermediate.

Since your DAC requires you to send 16 bit (that is 32 CPU cycles), and also requires you to toggle CS up and down (that is at least 2 more CPU cycles), the theoretical maximum sampling frequency you can achieve is 16 MHz / (32 + 2) = 470.6 ksamples per second. That is only 11.7 samples per one cycle of output sine wave.
To do so you need to disable all interrupts and write directly to output registers, you need either a shorter sine table, or skip some values.

In fact you can achieve any output frequency by skipping certain number of values in the sine table.

huangapple
  • 本文由 发表于 2023年3月9日 19:11:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/75683810.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定