слишком много лишнего

This commit is contained in:
KLASSENTS 2025-03-26 11:52:54 +07:00
parent 2a32262053
commit a682dc80a9
2 changed files with 0 additions and 592 deletions

View File

@ -1,156 +0,0 @@
#ifndef GA_HEADER_h // include guard
#define GA_HEADER_h
#ifdef __cplusplus
extern "C" {
#endif
#include <avr/io.h>
/*--------------------------------------------------*/
/*------------Often Configured Parameters-----------*/
/*--------------------------------------------------*/
#define SAMPLE_RATE 16000 // samples per second
#define DELAY 128000 // bytes of delay
/* Working buffer */
#define CMD_BUFFER_SIZE 8192 // size of working buffer (on heap)
/*--------------------------------------------------*/
/*---------------Public Functions-------------------*/
/*--------------------------------------------------*/
void AudioCodec_ADC_init(void) __attribute__((flatten));
void AudioCodec_ADC(uint16_t* _modvalue) __attribute__((hot, flatten));
void alaw_compress1(int16_t* linval, uint8_t* logval) __attribute__ ((hot, flatten));
void alaw_expand1(uint8_t* logval, int16_t* linval) __attribute__ ((hot, flatten));
void audioCodec_dsp( uint16_t* ch_A, uint16_t* ch_B) __attribute__ ((hot, flatten));
// prototype for the DSP function to be implemented.
// needs to at least provide *ch_A and *ch_B
// within Timer1 interrupt routine - time critical I/O. Keep it short and punchy!
/*--------------------------------------------------*/
void AudioCodec_ADC_init(void)
{
// setup ADCs
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(ADLAR) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); // 2.56V reference with external capacitor at AREF pin - left justify - start sampling MIC input ADC7
ADCSRA = _BV(ADEN) | _BV(ADSC) | _BV(ADATE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // ADC enable, auto trigger, ck/128 = 192kHz
ADCSRB = 0x00; // free running mode
DIDR0 = _BV(ADC7D) | _BV(ADC6D) | _BV(ADC2D) | _BV(ADC1D) | _BV(ADC0D); // turn off digital input for pin ADC6 Line and ADC7 Mic input (and ADC2, ADC1, & ADC0)
// Analogue Comparator Disable
// When the ACD bit is written logic one, the power to the Analogue Comparator is switched off.
// This bit can be set at any time to turn off the Analogue Comparator.
// This will reduce power consumption in Active and Idle mode.
// When changing the ACD bit, the Analogue Comparator Interrupt must be disabled by clearing the ACIE bit in ACSR.
// Otherwise an interrupt can occur when the ACD bit is changed.
ACSR &= ~_BV(ACIE);
ACSR |= _BV(ACD);
}
// adc sampling routine
void AudioCodec_ADC(uint16_t* _modvalue)
{
if (ADCSRA & _BV(ADIF)) // check if sample ready
{
*_modvalue = ADCW; // fetch ADCL first to freeze sample, then ADCH. It is done by the compiler.
ADCSRA |= _BV(ADIF); // reset the interrupt flag
}
}
/*
==========================================================================
FUNCTION NAME: alaw_compress11
DESCRIPTION: ALaw encoding rule according ITU-T Rec. G.711.
PROTOTYPE: int8_t alaw_compress1( int16_t linval )
PARAMETERS:
linval: (In) linear samples (only 12 MSBits are taken into account)
logval: (Out) compressed sample (8 bit right justified without sign extension)
RETURN VALUE: none.
==========================================================================
*/
void alaw_compress1 (int16_t* linval, uint8_t* logval)
{
uint16_t ix, iexp;
ix = *linval < 0 /* 0 <= ix < 2048 */
? ~*linval >> 4 /* 1's complement for negative values */
: *linval >> 4;
/* Do more, if exponent > 0 */
if (ix > 15) /* exponent=0 for ix <= 15 */
{
iexp = 1; /* first step: */
while (ix > 16 + 15) /* find mantissa and exponent */
{
ix >>= 1;
iexp++;
}
ix -= 16; /* second step: remove leading '1' */
ix += iexp << 4; /* now compute encoded value */
}
if (*linval >= 0) ix |= (0x0080); /* add sign bit */
*logval = (uint8_t)(ix ^ (0x0055)); /* toggle even bits */
}
/* ................... End of alaw_compress1() ..................... */
/*
==========================================================================
FUNCTION NAME: alaw_expand1
DESCRIPTION: ALaw decoding rule according ITU-T Rec. G.711.
PROTOTYPE: int16_t alaw_expand1( uint8_t logval )
PARAMETERS:
logval: (In) buffer with compressed samples (8 bit right justified,
without sign extension)
linval: (Out) buffer with linear samples (13 bits left justified)
RETURN VALUE: none.
============================================================================
*/
void alaw_expand1(uint8_t* logval, int16_t* linval)
{
uint8_t ix, iexp;
int16_t mant;
ix = (*logval ^ (0x55)); /* re-toggle toggled even bits */
ix &= 0x7F; /* remove sign bit */
iexp = ix >> 4; /* extract exponent */
mant = ix & 0x0f; /* now get mantissa */
if (iexp > 0)
mant = mant + 16; /* add leading '1', if exponent > 0 */
mant = (mant << 4) + (0x0008); /* now mantissa left justified and */
/* 1/2 quantization step added */
if (iexp > 1) /* now left shift according exponent */
mant = mant << (iexp - 1);
*linval = *logval > 127 /* invert, if negative sample */
? mant
: -mant;
}
/* ................... End of alaw_expand1() ..................... */
#ifdef __cplusplus
}
#endif
#endif // GA_HEADER_h end include guard

View File

@ -1,436 +0,0 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <util/atomic.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <SPI.h>
#include <SD.h>
// This example only works with Goldilocks Analogue, as DAC and SPI SRAM is required.
// INSTALLATION OF THE 4 FOLLOWING LIBRARIES REQUIRED!
// From Library: FreeRTOS
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
// From Library: AVR Real Time Clock Library
#include <AVR_RTC.h>
// From Library: Goldilocks Analogue DAC Library
#include <DAC.h>
// From Library: Goldilocks Analogue SPI RAM Library
#include <SPIRAM.h>
#include <SPIRAM_ringBuffer.h>
#include "GA_Header.h"
/*--------------------------------------------------*/
/*------------------- Globals ----------------------*/
/*--------------------------------------------------*/
DAC_value_t mod7_value; // location to store the ADC value before it is processed.
uint16_t ch_A_out; // storage for the values to be written to MCP4822
uint16_t ch_B_out;
SPIRAM_ringBuffer_t SRAM_delayBuffer; // structure to hold the SRAM ringbuffer info.
filter_t tx_filter; // instantiate a filter, which can be initialised to be a LPF (or BPF or HPF) later.
// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;
static uint8_t * Buff = NULL; /* Put a working buffer on heap later (with pvPortMalloc). */
// change this to match your SD shield or module;
// GoldilocksAnalogue SD shield: pin 14
uint8_t const chipSelect = 14;
// Create a Semaphore binary flag for the Serial Port. To ensure only single access.
SemaphoreHandle_t xSerialSemaphore;
// define two tasks to operate this test suite.
static void TaskReport( void *pvParameters ); // Report on the status reguarly using USART.
static void TaskAnalogue( void *pvParameters ); // Manage Analogue set-up, then sleep.
// Test the SPI EEPROM device, prior to building the SPI SRAM Delay loop.
static int8_t testSPIEEPROM( uint_farptr_t p1, uint16_t p2 );
// p1 = address of the SPI memory to be tested
// p2 = number of bytes to be tested (allocates a RAM buffer of this size too)
/*--------------------------------------------------*/
/*-------------------- Set Up ----------------------*/
/*--------------------------------------------------*/
void setup() {
// put your setup code here, to run once:
// Open serial communications and wait for port to open:
Serial.begin(38400);
Serial.println(F("Hello World!\n"));
setup_RTC_interrupt();
{
tm CurrTimeDate; // set up an array for the RTC info.
// <year yyyy> <month mm Jan=0> <date dd> <day d Sun=0> <hour hh> <minute mm> <second ss>
CurrTimeDate.tm_year = (uint8_t) ( 2016 - 1900 );
CurrTimeDate.tm_mon = (uint8_t) 1; // January is month 0, February is month 1, etc
CurrTimeDate.tm_mday = (uint8_t) 18;
CurrTimeDate.tm_hour = (uint8_t) 17;
CurrTimeDate.tm_min = (uint8_t) 16;
CurrTimeDate.tm_sec = (uint8_t) 0;
set_system_time( mktime( (tm*)&CurrTimeDate ) );
}
// Semaphores are useful to stop a task proceeding, where it should be stopped because it is using a resource, such as the Serial port.
// But they should only be used whilst the scheduler is running.
if ( xSerialSemaphore == NULL ) // Check to see if the Serial Semaphore has not been created.
{
xSerialSemaphore = xSemaphoreCreateMutex(); // mutex semaphore for Serial Port
if ( ( xSerialSemaphore ) != NULL )
xSemaphoreGive( ( xSerialSemaphore ) ); // make the Serial Port available
}
SPI.begin(); // warm up the SPI interface, so it can be used for the SPI RAM testing.
Serial.print(F("SPI SRAM Memory Testing: "));
if (testSPIEEPROM(RAM0_ADDR + 17, CMD_BUFFER_SIZE))
Serial.println(F("*** FAILED ***"));
else
Serial.println(F("PASSED"));
Serial.print(F("SPI EEPROM Memory Testing: "));
if (testSPIEEPROM(RAM1_ADDR + 17, CMD_BUFFER_SIZE))
Serial.println(F("*** FAILED ***\n"));
else
Serial.println(F("PASSED\n"));
// we'll use the SD Card initialization code from the utility libraries
// since we're just testing if the card is working!
Serial.print(F("\nInitializing SD card... "));
if (!card.init(SPI_HALF_SPEED, chipSelect)) {
Serial.println(F("initialization failed."));
Serial.println(F("Is a card inserted? You must insert a formatted SD Card to proceed."));
} else {
Serial.println(F("wiring is correct and a SD card is present."));
}
// print the type of card
Serial.print(F("\nCard type: "));
switch (card.type()) {
case SD_CARD_TYPE_SD1:
Serial.println(F("SD1"));
break;
case SD_CARD_TYPE_SD2:
Serial.println(F("SD2"));
break;
case SD_CARD_TYPE_SDHC:
Serial.println(F("SDHC"));
break;
default:
Serial.println(F("Unknown SD Card Type"));
break;
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
Serial.println(F("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card"));
} else {
// print the type and size of the first FAT-type volume
uint32_t volumesize;
Serial.print(F("\nVolume type is FAT"));
Serial.println(volume.fatType(), DEC);
Serial.println();
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize *= 512; // SD card blocks are always 512 bytes
Serial.print(F("Volume size (bytes): "));
Serial.println(volumesize);
Serial.print(F("Volume size (Kbytes): "));
volumesize /= 1024;
Serial.println(volumesize);
Serial.print(F("Volume size (Mbytes): "));
volumesize /= 1024;
Serial.println(volumesize);
Serial.println(F("\nFiles found on the card (name, date and size in bytes): "));
root.openRoot(volume);
// list all files in the card with date and size
root.ls(LS_R | LS_DATE | LS_SIZE);
}
// Now set up two tasks to help us with testing.
xTaskCreate(
TaskReport
, "RedLED" // report reguarly on the status of its stack and the tick values.
, 256 // Stack size
, NULL
, 2 // priority
, NULL ); // */
xTaskCreate(
TaskAnalogue
, "Analogue"
, 256 // This stack size can be checked & adjusted by reading Highwater
, NULL
, 1 // priority
, NULL ); // */
// Start the task scheduler, which takes over control of scheduling individual tasks.
// The scheduler is started in initVariant() found in variantHooks.c
}
/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/
static void TaskAnalogue(void *pvParameters) // Prepare the DAC
{
(void) pvParameters;
TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialised with the current tick
count. Note that this is the only time we access this variable. From this
point on xLastWakeTime is managed automatically by the xTaskDelayUntil()
API function. */
xLastWakeTime = xTaskGetTickCount();
// Create the SPI SRAM ring-buffer used by audio delay loop.
SPIRAM_ringBuffer_InitBuffer( &SRAM_delayBuffer, (uint_farptr_t)(RAM0_ADDR), sizeof(uint8_t) * DELAY);
// See if we can obtain the Serial Semaphore.
// If the semaphore is not available, wait 5 ticks to see if it becomes free.
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
// We were able to obtain the semaphore and can now access the shared resource.
// We want to have the Serial Port for us alone, as it takes some time to print,
// so we don't want it getting stolen during the middle of a conversion.
Serial.print(F("DAC_Codec_init "));
// initialise the USART 1 MSPIM bus specifically for DAC use, with the post-latch configuration.
// pre-latch for audio or AC signals (FALSE), or post-latch for single value setting or DC values (TRUE).
DAC_init(FALSE);
Serial.print(F("will "));
// Initialise the sample interrupt timer.
// set up the sampling Timer3 to 48000Hz (or lower), runs at audio sampling rate in Hz.
DAC_Timer3_init(SAMPLE_RATE);
Serial.print(F("very "));
// Initialise the filter to be a Low Pass Filter.
tx_filter.cutoff = 0xc000; // set filter to 3/8 of sample frequency.
setIIRFilterLPF( &tx_filter ); // initialise transmit sample filter
Serial.print(F("soon "));
// set up ADC sampling on the ADC7 (Microphone).
AudioCodec_ADC_init();
Serial.print (F("be "));
// Set the call back function to do the audio processing.
// Done this way so that we can change the audio handling depending on what we want to achieve.
DAC_setHandler(audioCodec_dsp, &ch_A_out, &ch_B_out);
Serial.println(F("done."));
xSemaphoreGive( xSerialSemaphore ); // Now free the Serial Port for others.
}
// vTaskSuspend(NULL); // Well, we're pretty much done here. Let's suspend the Task.
// vTaskEndScheduler(); // Or just kill the FreeRTOS scheduler. Rely on Timer3 Interrupt for regular output.
for (;;)
{
// See if we can obtain the Serial Semaphore.
// If the semaphore is not available, wait 5 ticks to see if it becomes free.
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
// We were able to obtain the semaphore and can now access the shared resource.
// We want to have the Serial Port for us alone, as it takes some time to print,
// so we don't want it getting stolen during the middle of a conversion.
Serial.print(F("Audio Stack HighWater @ "));
Serial.println(uxTaskGetStackHighWaterMark(NULL));
xSemaphoreGive( xSerialSemaphore ); // Now free the Serial Port for others.
}
xTaskDelayUntil( &xLastWakeTime, ( 8192 / portTICK_PERIOD_MS ) );
}
}
static void TaskReport(void *pvParameters) // report on the status of the device
{
(void) pvParameters;;
TickType_t xLastWakeTime;
/* The xLastWakeTime variable needs to be initialised with the current tick
count. Note that this is the only time we access this variable. From this
point on xLastWakeTime is managed automatically by the xTaskDelayUntil()
API function. */
xLastWakeTime = xTaskGetTickCount();
time_t currentTick; // set up a location for the current time stamp
for (;;)
{
// See if we can obtain the Serial Semaphore.
// If the semaphore is not available, wait 5 ticks to see if it becomes free.
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
// We were able to obtain the semaphore and can now access the shared resource.
// We want to have the Serial Port for us alone, as it takes some time to print,
// so we don't want it getting stolen during the middle of a conversion.
Serial.print(F("Report Stack HighWater @ "));
Serial.print(uxTaskGetStackHighWaterMark(NULL));
Serial.print(F(" Current Time: "));
time((time_t *)&currentTick);
Serial.println(ctime( (time_t *)&currentTick));
xSemaphoreGive( xSerialSemaphore ); // Now free the Serial Port for others.
}
xTaskDelayUntil( &xLastWakeTime, ( 2048 / portTICK_PERIOD_MS ) );
}
}
/*--------------------------------------------------*/
/*-------------------- Functions -------------------*/
/*--------------------------------------------------*/
static int8_t testSPIEEPROM( uint_farptr_t p1, uint16_t p2 )
{
int8_t ReturnCode;
if (Buff == NULL) // if there is no Buff buffer allocated (pointer is NULL), then allocate buffer.
if ( !(Buff = (uint8_t *) pvPortMalloc( sizeof(uint8_t) * CMD_BUFFER_SIZE )))
{
Serial.println(F("pvPortMalloc for *Buff fail..!"));
return SPIRAM_ERROR;
}
if (p2 >= CMD_BUFFER_SIZE) p2 = CMD_BUFFER_SIZE;
srand( p1 % 42 ); // create a random seed, based on 42.
for ( uint16_t i = 0; i < p2; ++i)
{
Buff[i] = (uint8_t) rand(); // fill the Buff with some pseudo random numbers.
}
Serial.print(F("Testing at 0x"));
Serial.print( (uint32_t)p1, HEX);
Serial.print(F(" for "));
Serial.print( p2, DEC);
Serial.println(F(" bytes."));
ReturnCode = SPIRAM_begin();
if (ReturnCode) return ReturnCode; // problem with opening the EEPROM / SRAM
uint_farptr_t FarAddress = p1;
ReturnCode = SPIRAM_write( FarAddress, Buff, (size_t)p2);
if (ReturnCode) return ReturnCode; /* error or disk full */
for (uint16_t i = 0; i < p2; ++i)
{
uint8_t read_result;
ReturnCode = SPIRAM_read( &read_result, (uint_farptr_t)(FarAddress + i), (size_t)1);
if (ReturnCode) return ReturnCode; /* error or disk full */
// Serial.print(F("Written 0x"));
// Serial.print( Buff[i], HEX);
// Serial.print(F(" Read 0x"));
// Serial.println( read_result, HEX);
if ( Buff[i] != read_result)
{
Serial.print(F("Error at Address 0x"));
Serial.print( (uint_farptr_t)(FarAddress + i), HEX);
Serial.print(F(" with 0x"));
Serial.println( read_result, HEX);
return SPIRAM_ERROR;
}
}
return SPIRAM_SUCCESS;
}
void audioCodec_dsp( uint16_t * ch_A, uint16_t * ch_B)
{
int16_t xn;
uint8_t cn;
if ( SPIRAM_ringBuffer_GetCount(&SRAM_delayBuffer) >= DELAY )
{
cn = SPIRAM_ringBuffer_Pop(&SRAM_delayBuffer);
}
else
{
cn = 0x80 ^ 0x55; // put A-Law nulled signal on the output.
}
alaw_expand1(&cn, &xn); // expand the A-Law compression
*ch_A = *ch_B = (uint16_t)(xn + 0x7fff); // put signal out on A & B channel.
AudioCodec_ADC(&mod7_value.u16);
xn = mod7_value.u16 - 0x7fe0; // centre the sample to 0 by subtracting 1/2 10bit range.
IIRFilter( &tx_filter, &xn); // filter sample train
alaw_compress1(&xn, &cn); // compress using A-Law
if ( SPIRAM_ringBuffer_GetCount(&SRAM_delayBuffer) <= DELAY )
{
SPIRAM_ringBuffer_Poke(&SRAM_delayBuffer, cn);
}
}
/*--------------------------------------------------*/
/*---------------------- Loop ----------------------*/
/*--------------------------------------------------*/
void loop() {
// Remember that loop() is simply the freeRTOS idle task.
// It is only something to do, when there's nothing else to do.
// There are several macros provided in the header file to put
// the device into sleep mode.
// SLEEP_MODE_IDLE (0)
// SLEEP_MODE_ADC _BV(SM0)
// SLEEP_MODE_PWR_DOWN _BV(SM1)
// SLEEP_MODE_PWR_SAVE (_BV(SM0) | _BV(SM1))
// SLEEP_MODE_STANDBY (_BV(SM1) | _BV(SM2))
// SLEEP_MODE_EXT_STANDBY (_BV(SM0) | _BV(SM1) | _BV(SM2))
set_sleep_mode( SLEEP_MODE_IDLE );
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
sleep_enable();
#if defined(BODS) && defined(BODSE) // Only if there is support to disable the brown-out detection.
sleep_bod_disable();
#endif
}
sleep_cpu(); // good night.
// Ugh. I've been woken up. Better disable sleep mode.
sleep_disable();
}