Write rate of DAC MCP4725 - c

I have a buffer which contains 16000 PCM samples of 8Khz 8-bit mono. I am trying to play it using 12 bit MCP4725 DAC. I have tried using micros() to control the write interval for the DAC. Here's my code -
uint8_t soundData[16000] = { 234,206,79,255,249,....,210,222 }; // 8Khz 8-bit mono
void setup() {
Serial.begin(115200);
Wire.begin(D2, D1);
delay(100); // delay 100 ms
Serial.flush();
delay(1000);
}
void value_write(uint16_t temp){
Wire.beginTransmission(0x62);
Wire.write(64);
Wire.write(temp >> 4); // the 8 most significant bits...
Wire.write((temp & 15) << 4); // the 4 least significant bits...
Wire.endTransmission();
}
void loop() {
unsigned long currentMicros = micros();
// 125 uS sampling for 8KHz signal
if(currentMicros - previousMicros > 125) {
Serial.print("Index: ");
Serial.println(indx);
uint16_t temp = map(soundData[indx++], 0, 255, 0, 4095);
value_write(temp);
}
}
The write should logically be completed within 2 seconds but takes way more time. Any help regarding successfully writing the PCM values to the DAC at 8000Hz is greatly appreciated.

Related

Timer on atmega328p

So we had a task in school that every 10ms a variable (millisekunden)
schould increase by 10. We were using the CTC Mode, i set the OCR0A to 157, the
prescaler was 1024. The variable (millisekunden) increases every 10ms for 10, and
when it reaches 1000 , we schould print it out, and repeat that every 1000.
I always get an error : avrdude: verification error, first mismatch at byte 0x0000
0x00 != 0x0c
avrdude: verification error; content mismatch
Can anyone check out my code if it is even correct programmed? Im using atmega328p
it has 16MHz. So i calculated 1/ 16 MHz * 1024(prescaler) * OCRA(157) and we get 10milli
seconds.
#include "Arduino.h"
unsigned long int t_ref;
volatile unsigned long int millisekunden; // milli seconds timer
unsigned long int last_msg;
char buffer[64];
unsigned int c;
void setup() {
// Timer 0
TCCR0A |= (1 << WGM01); // CTC Modus
TCCR0B |= (1 << CS02) | (1 << CS00); // Prescaler 1024
OCR0A = 155;
// Compare Interrupt
TIMSK0 |= (1 << OCIE0A);
Serial.begin(9600);
}
void loop() {
if (millisekunden - last_msg >= 1000) {
sprintf(buffer, "t=[%lu] PINB=[%2.2x]", millisekunden,PINB);
Serial.println(buffer);
last_msg = millisekunden;
}
}
// Timer-Interrupt-Routine
ISR(TIMER0_COMPA_vect) {
millisekunden = millisekunden + 10;
}
datasheet from µC : https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

I²C Communication from Scratch in C on Raspberry Pi in Linux

I want to create a small library for communication with I²C devices, especially the MPU6050 accelerometer / gyroscope module from scratch in C. Technically, I could use a library like wiringPi, but.. where is the fun with that. Right now I'm trying to write a function which scans all possible 7 bit addresses (0 - 127) and reads the acknowledge bit to find all 'active' addresses of connected I²C devices. To do that, I wrote a small library which can control the GPIO pins by writing to the coresponding GPIO files in /sys/class/gpio. It can for example setup a pin, set its direction (input or output), set its digital output and read a digital input from a pin. I tested all of these functions and they work great and fast.
For communication with the MPU6050 I²C slave I connected the power and ground pins of the MPU board to the Raspberry's GPIO power and ground pins and the SDA and SCL lines to GPIO pins 14 and 15. I read a lot about I²C recently and I do understand how it works. The problem is, that my code to scan through all addresses does not work. Here's my code:
#include <stdio.h>
#include <unistd.h>
#include "string.h"
#include "gpio.h"
#define SCL 14
#define SDA 15
#define FREQ 100000
#define high 1
#define low 0
char binret[8];
void scanI2C();
void charToBin(unsigned char);
void delay();
int main () {
setupPin(SCL, OUTPUT);
setupPin(SDA, OUTPUT);
scanI2C();
}
void scanI2C() {
int addr = 0;
for (int i = 90; i < 128; i++) {
charToBin(i);
// Start Condition
setPin(SDA, high);
setPin(SCL, high);
delay();
setPin(SDA, low);
for (int j = 0; j < 9; j++) {
delay();
setPin(SCL, low);
delay();
setPin(SCL, high);
if (j < 7) {
setPin(SDA, binret[j+1]);
}
// WRITE Bit
if (j == 7) {
setPin(SDA, high);
}
// Listen for ACK bit
if (j == 8) {
setPinDirection(SDA, INPUT);
printf("Checking Address %d (%d%d%d%d%d%d%d%d)", i, binret[0], binret[1], binret[2], binret[3], binret[4], binret[5], binret[6], binret[7]);
if (readPin(SDA) <= 0.5) {
printf(" Bingo!");
}
setPinDirection(SDA, OUTPUT);
printf("\n");
}
}
// Stop Condition
setPin(SCL, low);
delay();
setPin(SDA, high);
delay();
setPin(SCL, high);
delay();
delay();
delay();
delay();
delay();
}
}
void charToBin(unsigned char a) {
memset(binret, 0, sizeof(binret));
int val = 128;
for (int i = 0; i < 8; i++) {
int bit = a & val;
if (bit != 0) {
binret[i] = 1;
}
val /= 2;
}
}
void delay() {
usleep(1000000.0/FREQ);
}
Since I do actually know the address of the MPU6050 I²C slave to be 0x69 or 105 in decimal, I would expect the output to be something like this:
...
Checking Address 103 (01100111)
Checking Address 104 (01101000)
Checking Address 105 (01101001) Bingo!
Checking Address 106 (01101010)
Checking Address 107 (01101011)
Checking Address 108 (01101100)
Checking Address 109 (01101101)
Checking Address 110 (01101110)
...
But no, I don't get a Bingo! at address 105, which means that my I²C communication is definitely not working. Advice on how to address this issue is very much appreciated! Thank you and have a nice day :)
Typically it is the LSB of the 8-bit "address" that is the R/W bit. If you have a device with address 105 I would expect it to respond when your 8-bit address is 210 or 211. Have you tried the entire address space?
Does readPin() return a float? If not, why are you comparing to a float?
It looks like you are changing SDA while SCL is high and you are sending the address bits. I don't think that is allowed.
Do you have a pullup resistor on SDA?
Have you verified signal levels and timing with an oscilloscope?

attiny85 bit bang uart with arduino

I have tried to implement TX only uart for ATTiny85 and receive the bits using arduino micro. (similiar question did not help since it is quite different to my situation)
My intend is to be able to print via attiny85 -> arduino -> console so I can debug the attiny85, since I don't have oscilloscope available.
attiny85 fuses are: "efuse:w:0xff:m -U hfuse:w:0xdf:m -U lfuse:w:0xf1:m" aka. 16MHz F_CPU
arduino also seems to have 16MHz F_CPU
Similiar to the mentioned question attiny85 sends bits via timer0 ISR one bit at time:
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define TX_PIN PB0
volatile uint16_t tx_shift_reg = 0;
ISR(TIMER0_COMPA_vect) {
uint16_t local_tx_shift_reg = tx_shift_reg;
if( local_tx_shift_reg & 0x01 ) {
PORTB |= _BV(TX_PIN);
} else {
PORTB &= ~_BV(TX_PIN);
}
local_tx_shift_reg >>= 1;
if(!local_tx_shift_reg) {
// Stop timer0.
GTCCR |= (1<<TSM) | (1<<PSR0);
}
tx_shift_reg = local_tx_shift_reg;
}
void UART_tx(char byte) {
uint16_t local_tx_shift_reg = tx_shift_reg;
local_tx_shift_reg = (0b1<<9) | ((uint16_t)byte<<1);
tx_shift_reg = local_tx_shift_reg;
TCNT0 = 0;
TCCR0B |= (1<<CS02)|(1<<CS00); // 1024 prescaler
GTCCR &= ~(1<<TSM);
}
void UART_tx_char(char c) {
UART_tx( c );
// wait until transmission is finished
while(tx_shift_reg);
}
void UART_init() {
cli()
// set TX pins as output
DDRB |= (1<<TX_PIN);
PORTB |= (1<<TX_PIN);
// set timer0 to CTC mode, keep it halted.
TCCR0A |= (1<<WGM01);
TCCR0B = 0;
// enable interrupt
TIMSK |= (1<<OCIE0A);
OCR0A = 128;
OCR0B = 128;
TCNT0 = 0;
GTCCR |= (1<<TSM);
sei();
}
void main(void)
{
UART_init();
while(1) {
for(char c = 1; c < 128; ++c) {
UART_tx_char(c);
_delay_ms(100);
}
}
}
Then arduino receives the bits:
/*
* ATtiny85 bit-bang uart monitor for ATmega32u4
*/
#define LED_PIN 13
#define RX_PIN 7
// rx_state == 0 // timer1 not running
// rx_state == 1 // receive in progress
// rx_state == 2 // data ready in rx_data_reg
volatile int rx_state = 0;
volatile int rx_bit_nro = 0;
volatile uint16_t rx_shift_reg = 0;
volatile uint16_t rx_data_reg = 0;
void rx_start_interupt() {
if(rx_state == 0) {
digitalWrite(LED_PIN, HIGH);
while(digitalRead(RX_PIN));
// Start timer1
rx_state++;
TCNT1 = 0;
TCCR1B = (1 << WGM12) | (1 <<CS12) | (1 << CS10);
}
}
ISR(TIMER1_COMPA_vect) {
uint16_t bit = digitalRead(RX_PIN) > 0;
rx_shift_reg >>= 1;
rx_shift_reg |= (bit << 7);
++rx_bit_nro;
if(rx_bit_nro == 9) {
// Stop timer.
TCCR1B = 0;
TCNT1 = 0;
rx_data_reg = rx_shift_reg;
rx_shift_reg = 0;
rx_bit_nro = 0;
rx_state++;
digitalWrite(LED_PIN, LOW);
}
}
void setup() {
noInterrupts();
// Program timer1 for UART bit bang receive.
TCCR1A = 0; // set entire TCCR1A register to 0 (stops it)
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
OCR1A = 128;
TIMSK1 |= (1 << OCIE1A);
interrupts();
pinMode(LED_PIN, OUTPUT);
pinMode(RX_PIN, INPUT);
// Attach RX start interupt.
pinMode(digitalPinToInterrupt(RX_PIN), INPUT);
attachInterrupt(digitalPinToInterrupt(RX_PIN), rx_start_interupt, FALLING);
Serial.begin(9600);
while(!Serial);
Serial.print("F_CPU:");
Serial.println(F_CPU,DEC);
Serial.println("Waiting for data from attiny85...");
}
void loop() {
if(rx_state == 2) {
uint16_t local_rx_data = rx_data_reg;
rx_state = 0;
Serial.println(local_rx_data,HEX);
}
}
I have tried pretty much everything to make it work, but received bytes come back garbace.
What am I missing?
Note: I'm using timer0 on attiny85 and timer1 on arduino.
Solved: switching ISR to TIMER1_COMPAB_vect and OCR1B = 64 actually works! Yay!
I recently ran into this issue of serial comms coming out as garbage on the other end. In my case, the ATtiny85 was sending bits to my laptop using an USB to TTL UART converter which had worked beautifully in other situations, but, I was just getting garbage in the Arduino IDE serial monitor.
I found a forum post which mentioned the possibility of calibrating OSCCAL.
I get a little bit fancier in my related blog post, but I tested the theory that I should calibrate OSCCAL using this code:
#include <SoftwareSerial.h>
SoftwareSerial comm(-1, 0);
static const int anchor = 128;
void
print_osccal(int v) {
comm.println(F("********************************"));
comm.print(F("OSCCAL = "));
comm.println(v);
comm.println(F("********************************"));
}
void
setup() {
delay(5000);
comm.begin(300);
OSCCAL = anchor;
print_osccal(anchor);
delay(5000);
}
void
loop() {
int x;
for (int i = 1; i < 128; ++i) {
x = anchor + i;
OSCCAL = x;
print_osccal(x);
delay(1000);
x = anchor - i;
OSCCAL = x;
print_osccal(x);
delay(1000);
}
}
It was a revelation seeing garbage all of a sudden transform to nicely formatted messages in the serial monitor (and, of course, back to garbage as the search is an infinite loop).
Now, the ATtiny85's internal oscillator can only support 1 MHz and 8 MHz. As I understand it, OSCCAL exists because this internal oscillator is 1) not very accurate and 2) is very sensitive the temperature.
If the ATtiny85 is set to run at 16MHz, it needs a reliable, external oscillator, and no amount of fiddling with OSCCAL might help. But, it did in my case allow me to discover the value(s) which made SoftwareSerial tick at 8 MHz and a range of baud rates from 300 to 38400.
This allowed me to get the right value for the bit banging UART to work with the 1MHz clock which is not supported by SoftwareSerial.

Two timers to produce the same frequency but one of them is Looped 67 times

Pulse generation
#include <Arduino.h>
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
DDRB = 0xFF;
ICR1 = 3124;// set the 5Hz frequency at the output
TCCR1A |=( 1 <<WGM12);//set timer to CTC mode
TCCR1B |=( 1 << CS12)|( 1 << CS10);//set prescaler to 1024
sei();// set interrupt
while(1)
{
}
}
ISR(TIMER1_COMPA_vect)
{
//Action to be done over 200ms
TCCR2A = 0x63; // 0110 0011
TCCR2B = 0x08 | 6; // Prescale=256
OCR2A = 185-1; // TOP
OCR2B = (int) (OCR2A * 0.5);
pinMode(11, OUTPUT); // OC2a
pinMode(3, OUTPUT); // OC2b
}
I am using AVR Atmega328P, I would like to create a PWM pulse signal with two 5Hz frequencies generated from one Timer1, that will generate different duty cycles such that one of the frequencies has to be looped 67 times in one cycle of the other frequency. I have attached an image of how I'd like the pulses to look like on the oscilloscope. Would you please help me.
If you want 5 Hz and 335 Hz ("67 * 5 Hz") using a single timer, then you'd want to set the timer to the highest frequency and then have a divider in software (in the IRQ handler) to get the lower frequency.
However, for perfect square waves you want an IRQ for "rising edge" and another IRQ for "falling edge", so you'd want the timer's frequency to be double the highest frequency (e.g. 670 Hz, not 335 Hz).
For example, maybe something like:
ISR(TIMER1_COMPA_vect)
{
static counter1 = 1;
static counter2 = 1;
// Actions to be done 670 times per second
counter1--;
if(counter1 == 0) {
// Set output1 to "high"
counter1 = 134; // 670 Hz / 134 = 5 Hz
} else if(counter1 == 67) {
// Set output1 to "low"
}
counter2--;
if(counter2 == 0) {
// Set output2 to "high"
counter2 = 2; // 670 Hz / 2 = 335 Hz
} else if(counter2 == 1) {
// Set output2 to "low"
}
}

is it possible compare a 16-bit value with a 8-bit compare match ISR

I am trying to make a servo controller that have a higher resolution than the ATtiny85 8-bit timer/counter. So far I have managed to get about 2000 positions on my servo (1µs/step) within a time frame of 21'000 µs. I have also managed to move 5 servos sequential and with different speed, but now I want to move them synchronous.
My biggest problem is that I don't get how I should make it happen! I have looked around on other servo codes including servo8bit library and tried to find a way. It seems that most of the examples uses compare match ISR to move the servos "at the same time", my problem is that I have a 16-bit integer that I want to compare.
Is there a way to do some magic so I can use the 8-bit compare match ISR with my 16-bit integer? Or does anyone of you have some other suggestions on how I can move my servos synchronous without using compare match ISR?
I hope my questions make sense!
Since I don't really have any code to show yet (only flawed attempts without compar match ISR that makes no sense) I post the link to my TinyServo code if it helps.
EDIT 1:
Here is the part of the code I mentioned and didn't post the first time:
void servoMove(void)
{
uint16_t nextPulse = hPulse[0];
timerSetup (); //16-bit setup for counter
for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
if ( (oTime > nextPulse) && (channel < sizeof(servo)/sizeof(servo[0])) ) //check if HIGH pulse (pos) is done
{
PORTB &= ~(1 << servo[channel]);
if (i+1 < sizeof(hPulse)/sizeof(hPulse[0]))
{
nextPulse += hPulse[i+1];
}
channel++;
}
else
{
channel = 0;
oTime = 0; //resets 16-bit variable
tot_overflow = 0; //resets tot_overflow variable
TIFR |= (1 << TOV1); // clear counter1 overflow-flag
TCNT1 = 0; //resets Timer/Counter1
}
}
for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
if ( (oTime > tPulse - nextPulse) && (channel < sizeof(servo)/sizeof(servo[0])) ) //check if LOW pulse (period) is done
{
PORTB |= (1 << servo[channel]);
nextPulse -= hPulse[i];
channel++;
}
}
}
void servoPosSet(volatile uint16_t pos[], uint8_t size)
{
for (i = 0; i < size; i++)
{
hPulse[i] = pos[i];
}
}
int main(void)
{
TCCR1 |= (1 << CS12); //set Timer/Counter1 prescaler to increment every 1 µs (PCK/8)
for (channel = 0; channel < size); channel++)
{
DDRB |= (1 << servo[channel]); //sets PB0-PB4 as output pins
}
channel = 0;
uint16_t pos[] = {2000, 1500, 1900, 1300, 1700};
uint8_t size = 5;
while(1)
{
servoPosSet(pos);
servoMove();
}
}
EDIT 2:
This is an illustration of how I think the code should work:
...but it does not!
If you have nothing else to do during the pulse, you could use a busy
loop instead of interrupts:
#include <avr/io.h>
#include <util/delay_basic.h>
/* Send a pulse of width = 4*count cycles. */
void pulse(uint16_t count, uint8_t channel)
{
uint8_t mask = 1 << channel,
old_port = PORTB,
high = old_port | mask,
low = old_port & ~mask;
PORTB = high;
_delay_loop_2(count);
PORTB = low;
}
This will give you a resolution of 4 clock cycles, or 0.5 µs with a
8 MHz clock.
Sending the pulses to the 5 servos should take at most 10 ms. Since
you repeat the pulse train every 21 ms, this leaves you 11 ms
to compute the next set of positions, which should be plenty. You could
program a timer to wake you up every 21 ms, then your main() may
look like:
int main(void)
{
static uint16_t pos[] = {4000, 3000, 3800, 2600, 3400};
uint8_t i;
/* Wake up every 21 ms. */
setup_timer();
sleep_enable();
for (;;) {
/* Update the servos. */
for (i = 0; i < 5; i++) pulse(pos[i], i);
/* Compute the next set of positions. */
...
/* Wait for timer interrupt. */
sleep_cpu();
}
}

Resources