2020-03-14 22:30:05 +01:00
|
|
|
/* Copyright © 2020 tyrolyean
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "avr.h"
|
|
|
|
#include "dac.h"
|
|
|
|
#include "structures.h"
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
uint8_t dac_mode = DAC_MODE_SINE;
|
|
|
|
int16_t dac_frequency_deviation = 0;
|
|
|
|
|
|
|
|
void write_to_dac(uint8_t addr, uint8_t data){
|
|
|
|
|
|
|
|
|
|
|
|
set_addr(addr);
|
|
|
|
DATA_DDR_REG = 0xFF;
|
|
|
|
DATA_REG = data;
|
|
|
|
CTRL_REG &= ~(1<<WR_SHIFT) & ~(1<<CS_DAC_SHIFT);
|
|
|
|
|
|
|
|
_delay_us(BUS_HOLD_US); /*Wait for the data and signal lanes to become stable*/
|
|
|
|
|
|
|
|
CTRL_REG |= 1<<CS_DAC_SHIFT;
|
|
|
|
CTRL_REG |= 1<<WR_SHIFT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t read_from_dac(uint8_t addr){
|
|
|
|
|
|
|
|
uint8_t data = 0x00;
|
|
|
|
|
|
|
|
set_addr(addr);
|
|
|
|
DATA_DDR_REG = 0x00;
|
|
|
|
|
|
|
|
/* Sometimes the avr "forgets" to alter the port register for one cycle
|
|
|
|
* which usually isn't a problem but has lead to instability. Worthy
|
|
|
|
* one clock cycle */
|
|
|
|
DATA_REG = 0x00;
|
|
|
|
CTRL_REG &= ~(1<<RD_SHIFT) & ~(1<<CS_DAC_SHIFT);
|
|
|
|
|
|
|
|
_delay_us(BUS_HOLD_US); /* Wait for the data and signal lanes to become
|
|
|
|
* stable*/
|
|
|
|
data = PINF;
|
|
|
|
CTRL_REG |= 1<<CS_DAC_SHIFT | 1<<RD_SHIFT;
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void feed_dac(){
|
2020-03-23 10:04:40 +01:00
|
|
|
/* Internal counter for positioning inside the currently playing
|
|
|
|
* waveform */
|
2020-03-14 22:30:05 +01:00
|
|
|
static uint8_t threash = 0x00;
|
2020-03-23 10:04:40 +01:00
|
|
|
/* Used to generate the desired frequency offset if the waveform should
|
|
|
|
* be made "longer" --> the frequency made lower from baseline
|
|
|
|
*/
|
2020-03-14 22:30:05 +01:00
|
|
|
static int16_t freq_delay_cnt = 0x00;
|
|
|
|
switch(dac_mode){
|
|
|
|
|
|
|
|
default:
|
|
|
|
case DAC_MODE_SILENT:
|
|
|
|
for(uint8_t i = 0; i < 0xFF; i++){
|
|
|
|
write_to_dac(i%2, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DAC_MODE_SINE:
|
|
|
|
/* Generates a sine from a predetermined sine table in program
|
2020-03-23 10:04:40 +01:00
|
|
|
* space */
|
2020-03-14 22:30:05 +01:00
|
|
|
for(uint8_t i = 0; i < (0xFF/2); i++){
|
|
|
|
write_to_dac(1,
|
|
|
|
pgm_read_byte(&sine_table[threash]));
|
|
|
|
write_to_dac(0,
|
|
|
|
pgm_read_byte(&sine_table[threash]));
|
|
|
|
|
|
|
|
if(dac_frequency_deviation >=0){
|
|
|
|
freq_delay_cnt++;
|
|
|
|
if(freq_delay_cnt >=
|
|
|
|
dac_frequency_deviation){
|
|
|
|
freq_delay_cnt = 0;
|
|
|
|
threash++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
threash -= dac_frequency_deviation;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DAC_MODE_SQUARE:
|
|
|
|
/* Generates a square wave tone */
|
|
|
|
for(uint8_t i = 0; i < (0xFF/2); i++){
|
|
|
|
if(threash > (0xFF/2)){
|
|
|
|
write_to_dac(0, 0xFF);
|
|
|
|
write_to_dac(1, 0xFF);
|
|
|
|
}else{
|
|
|
|
write_to_dac(0, 0);
|
|
|
|
write_to_dac(1, 0);
|
|
|
|
}
|
|
|
|
if(dac_frequency_deviation >=0){
|
|
|
|
freq_delay_cnt++;
|
|
|
|
if(freq_delay_cnt >=
|
|
|
|
dac_frequency_deviation){
|
|
|
|
freq_delay_cnt = 0;
|
|
|
|
threash++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
threash -= dac_frequency_deviation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DAC_MODE_SAW:
|
|
|
|
/* Generates a saw wave tone */
|
|
|
|
for(uint8_t i = 0; i < (0xFF/2); i++){
|
|
|
|
write_to_dac(0, threash);
|
|
|
|
write_to_dac(1, threash);
|
|
|
|
if(dac_frequency_deviation >=0){
|
|
|
|
freq_delay_cnt++;
|
|
|
|
if(freq_delay_cnt >=
|
|
|
|
dac_frequency_deviation){
|
|
|
|
freq_delay_cnt = 0;
|
|
|
|
threash++;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
threash -= dac_frequency_deviation;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DAC_MODE_NOISE:
|
|
|
|
/* Generates white noise from a predetermined LUT
|
|
|
|
*/
|
|
|
|
for(uint8_t i = 0; i < (0xFF/2); i++){
|
|
|
|
static uint16_t noise_cnt = 0;
|
|
|
|
write_to_dac(1,
|
|
|
|
pgm_read_byte(&noise_table[noise_cnt]));
|
|
|
|
write_to_dac(0,
|
|
|
|
pgm_read_byte(&noise_table[noise_cnt]));
|
|
|
|
|
|
|
|
noise_cnt++; /* Doesn't have frequency diversion
|
|
|
|
*/
|
|
|
|
if(noise_cnt >= 1024){
|
|
|
|
noise_cnt = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DAC_MODE_TRIANGLE:
|
|
|
|
/* Generates a triangle wave tone */
|
|
|
|
for(uint8_t i = 0; i < (0xFF/2); i++){
|
|
|
|
static int8_t direction = 1;
|
|
|
|
if((threash == 0xFF) | !threash){
|
|
|
|
direction = -direction;
|
|
|
|
}
|
|
|
|
write_to_dac(0, threash);
|
|
|
|
write_to_dac(1, threash);
|
|
|
|
if(dac_frequency_deviation >=0){
|
|
|
|
freq_delay_cnt++;
|
|
|
|
if(freq_delay_cnt >=
|
|
|
|
dac_frequency_deviation){
|
|
|
|
freq_delay_cnt = 0;
|
|
|
|
|
|
|
|
threash += direction;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}else{
|
|
|
|
if((dac_frequency_deviation *
|
|
|
|
direction) >
|
|
|
|
(0xFF - threash)){
|
|
|
|
threash = 0xFF;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
threash = (dac_frequency_deviation *
|
|
|
|
direction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void routine_dac(){
|
|
|
|
|
|
|
|
uint8_t received = read_from_dac(0x00);
|
|
|
|
if(!(received & (0x01<<0))){
|
|
|
|
feed_dac();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|