kopia lustrzana https://github.com/amedes/pico_tnc
add PIO program for Sigma Delta 1-bit DAC
rodzic
0b9de7ccaf
commit
ef4e067a1d
|
@ -22,6 +22,8 @@ add_executable(pico_tnc
|
|||
kiss.c
|
||||
)
|
||||
|
||||
pico_generate_pio_header(pico_tnc ${CMAKE_CURRENT_LIST_DIR}/pio_dac.pio)
|
||||
|
||||
target_include_directories(pico_tnc PRIVATE
|
||||
include
|
||||
)
|
||||
|
@ -35,7 +37,7 @@ target_link_libraries(pico_tnc
|
|||
hardware_pwm
|
||||
hardware_uart
|
||||
# For the dummy output:
|
||||
#hardware_pio
|
||||
hardware_pio
|
||||
#pico_multicore
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
;
|
||||
; Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||
;
|
||||
; SPDX-License-Identifier: BSD-3-Clause
|
||||
;
|
||||
|
||||
.program pio_dac
|
||||
|
||||
; Repeatedly get one word of data from the TX FIFO, stalling when the FIFO is
|
||||
; empty. Write the least significant bit to the OUT pin group.
|
||||
|
||||
.wrap_target
|
||||
out pins, 1
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
static inline void pio_dac_program_init(PIO pio, uint sm, uint offset, uint pin, float fs) {
|
||||
pio_sm_config c = pio_dac_program_get_default_config(offset);
|
||||
|
||||
// Map the state machine's OUT pin group to one pin, namely the `pin`
|
||||
// parameter to this function.
|
||||
sm_config_set_out_shift(&c, true, true, 32);
|
||||
sm_config_set_out_pins(&c, pin, 1);
|
||||
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / fs);
|
||||
|
||||
// Set this pin's GPIO function (connect PIO to the pad)
|
||||
pio_gpio_init(pio, pin);
|
||||
|
||||
// Set the pin direction to output at the PIO
|
||||
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
||||
|
||||
// Load our configuration, and jump to the start of the program
|
||||
pio_sm_init(pio, sm, offset, &c);
|
||||
|
||||
// Set the state machine running
|
||||
pio_sm_set_enabled(pio, sm, true);
|
||||
}
|
||||
%}
|
|
@ -1,29 +1,8 @@
|
|||
/*
|
||||
Copyright (c) 2021, JN1DFF
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* Copyright (c) 2021 JN1DFF
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* send.c - send packet
|
||||
|
@ -37,15 +16,18 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "hardware/pwm.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "hardware/sync.h"
|
||||
#include "hardware/pio.h"
|
||||
#include "hardware/structs/uart.h"
|
||||
#include "pico/util/queue.h"
|
||||
|
||||
#include "pio_dac.pio.h"
|
||||
|
||||
#include "tnc.h"
|
||||
#include "send.h"
|
||||
#include "ax25.h"
|
||||
|
||||
//#include "wave_table.h"
|
||||
#include "wave_table_132mhz.h"
|
||||
#include "wave_table.h"
|
||||
|
||||
static const int pwm_pins[] = {
|
||||
10, // port 0
|
||||
|
@ -75,31 +57,30 @@ static void __isr dma_handler(void)
|
|||
for (int i = 0; i < PORT_N; i++) {
|
||||
tnc_t *tp = &tnc[i];
|
||||
|
||||
if (int_status & tp->data_chan_mask) {
|
||||
if (int_status & tp->data_chan_mask) {
|
||||
|
||||
// generate modem signal
|
||||
uint32_t *addr;
|
||||
if (queue_try_remove(&tp->dac_queue, &addr)) {
|
||||
// generate modem signal
|
||||
uint32_t *addr;
|
||||
if (queue_try_remove(&tp->dac_queue, &addr)) {
|
||||
|
||||
dma_channel_set_read_addr(tp->ctrl_chan, addr, true);
|
||||
dma_channel_set_read_addr(tp->ctrl_chan, addr, true);
|
||||
#if 0
|
||||
printf("dma_hander: block = %p\n", &block[0]);
|
||||
for (int i = 0; i < CONTROL_N + 1; i++) {
|
||||
printf("block[%d] = %p\n", i, block[i]);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
gpio_put(tp->ptt_pin, 0); // PTT off
|
||||
pwm_set_chan_level(tp->pwm_slice, PWM_CHAN_A, 0); // set pwm level 0
|
||||
tp->busy = false;
|
||||
//printf("(%u) dma_handler: queue is empty, port = %d, data_chan = %d, ints = %08x\n", tnc_time(), tp->port, tp->data_chan, int_status);
|
||||
} else {
|
||||
gpio_put(tp->ptt_pin, 0); // PTT off
|
||||
//pwm_set_chan_level(tp->pwm_slice, PWM_CHAN_A, 0); // set pwm level 0
|
||||
tp->busy = false;
|
||||
//printf("(%u) dma_handler: queue is empty, port = %d, data_chan = %d, ints = %08x\n", tnc_time(), tp->port, tp->data_chan, int_status);
|
||||
}
|
||||
//dma_hw->ints0 = tp->data_chan_mask;
|
||||
}
|
||||
//dma_hw->ints0 = tp->data_chan_mask;
|
||||
}
|
||||
} // for
|
||||
|
||||
dma_hw->ints0 = int_status;
|
||||
|
||||
}
|
||||
|
||||
static void send_start(tnc_t *tp)
|
||||
|
@ -108,7 +89,7 @@ static void send_start(tnc_t *tp)
|
|||
gpio_put(tp->ptt_pin, 1); // PTT on
|
||||
tp->busy = true;
|
||||
//printf("restart dma, ctrl = %08x, port = %d\n", dma_hw->ch[tp->data_chan].ctrl_trig, tp->port);
|
||||
dma_channel_set_read_addr(tp->data_chan, NULL, true);
|
||||
dma_channel_set_read_addr(tp->data_chan, NULL, true); // trigger NULL interrupt
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,7 +174,7 @@ int send_byte(tnc_t *tp, uint8_t data, bool bit_stuff)
|
|||
tp->dma_blocks[tp->next][idx] = NULL;
|
||||
|
||||
// send fsk data to dac queue
|
||||
uint16_t const **block = &tp->dma_blocks[tp->next][0];
|
||||
uint32_t const **block = &tp->dma_blocks[tp->next][0];
|
||||
if (queue_try_add(&tp->dac_queue, &block)) {
|
||||
#if 0
|
||||
if (!tp->busy) {
|
||||
|
@ -223,7 +204,12 @@ int send_byte(tnc_t *tp, uint8_t data, bool bit_stuff)
|
|||
void send_init(void)
|
||||
{
|
||||
// set system clock, PWM uses system clock
|
||||
set_sys_clock_khz(SYS_CLK_KHZ, true);
|
||||
//set_sys_clock_khz(SYS_CLK_KHZ, true);
|
||||
|
||||
// pio_dac initialize
|
||||
PIO pio = pio0;
|
||||
// load pio_dac program
|
||||
uint offset = pio_add_program(pio, &pio_dac_program);
|
||||
|
||||
// initialize tnc[]
|
||||
for (int i = 0; i < PORT_N; i++) {
|
||||
|
@ -241,6 +227,7 @@ void send_init(void)
|
|||
gpio_set_dir(tp->ptt_pin, true); // output
|
||||
gpio_put(tp->ptt_pin, 0);
|
||||
|
||||
#if 0
|
||||
// PWM pins
|
||||
tp->pwm_pin = pwm_pins[i];
|
||||
// PWM configuration
|
||||
|
@ -253,6 +240,12 @@ void send_init(void)
|
|||
pwm_config_set_clkdiv_int(&pc, 1); // 1.0
|
||||
pwm_config_set_wrap(&pc, PWM_CYCLE - 1);
|
||||
pwm_init(tp->pwm_slice, &pc, true); // start PWM
|
||||
#endif
|
||||
|
||||
// PIO
|
||||
// find free state machine
|
||||
uint sm = pio_claim_unused_sm(pio, true);
|
||||
pio_dac_program_init(pio, sm, offset, pwm_pins[i], PIO_DAC_FS);
|
||||
|
||||
// DMA
|
||||
tp->ctrl_chan = dma_claim_unused_channel(true);
|
||||
|
@ -278,8 +271,8 @@ void send_init(void)
|
|||
|
||||
// DMA data channel
|
||||
dc = dma_channel_get_default_config(tp->data_chan);
|
||||
channel_config_set_transfer_data_size(&dc, DMA_SIZE_16); // PWM level is 16 bits
|
||||
channel_config_set_dreq(&dc, DREQ_PWM_WRAP0 + tp->pwm_slice);
|
||||
channel_config_set_transfer_data_size(&dc, DMA_SIZE_32); // pio_dac data size, 32bit
|
||||
channel_config_set_dreq(&dc, pio_get_dreq(pio, sm, true)); // pio sm, TX
|
||||
channel_config_set_chain_to(&dc, tp->ctrl_chan);
|
||||
channel_config_set_irq_quiet(&dc, true);
|
||||
// set high priority bit
|
||||
|
@ -288,7 +281,7 @@ void send_init(void)
|
|||
dma_channel_configure(
|
||||
tp->data_chan,
|
||||
&dc,
|
||||
&pwm_hw->slice[tp->pwm_slice].cc,
|
||||
&pio0_hw->txf[sm], // The initial write address
|
||||
NULL, // Initial read address and transfer count are unimportant;
|
||||
BIT_CYCLE, // audio data of 1/1200 s
|
||||
false // Don't start yet.
|
||||
|
|
|
@ -33,7 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
//#include "cmd.h"
|
||||
|
||||
// number of ports
|
||||
#define PORT_N 1 // number of ports, 1..3
|
||||
#define PORT_N 3 // number of ports, 1..3
|
||||
|
||||
#define BAUD_RATE 1200
|
||||
#define SAMPLING_N 11
|
||||
|
@ -163,7 +163,7 @@ typedef struct TNC {
|
|||
int cnt_one;
|
||||
|
||||
// wave buffer for DMA
|
||||
uint16_t const *dma_blocks[DAC_BLOCK_LEN][CONTROL_N + 1];
|
||||
uint32_t const *dma_blocks[DAC_BLOCK_LEN][CONTROL_N + 1];
|
||||
|
||||
// send data queue
|
||||
queue_t send_queue;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* Copyright (c) 2021 JN1DFF
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
sine wave table for Bell202 AFSK signal
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define SYS_CLK_KHZ 132000
|
||||
#define BIT_CYCLE 440
|
||||
#define MARK_CYCLE 440
|
||||
#define SPACE_CYCLE 240
|
||||
#define MARK_TAB_LEN 807
|
||||
#define SPACE_TAB_LEN 640
|
||||
#define PWM_CYCLE 250
|
||||
#endif
|
||||
|
||||
#define BAUD 1200 // bit rate
|
||||
#define BIT_CYCLE 66 // DMA data words in 1/1200s
|
||||
#define MARK_TAB_LEN 121 // 66 * 5/6 + 66
|
||||
#define SPACE_TAB_LEN 96 // 36 * 5/6 + 66
|
||||
#define PHASE_CYCLE 6
|
||||
#define PIO_DAC_FS (BIT_CYCLE * BAUD * 32)
|
||||
|
||||
/* sine table for delta sigma modulation, 1200Hz */
|
||||
static const uint32_t mark_tab[MARK_TAB_LEN] = {
|
||||
0x20000200, 0x00010000, 0x00040004, 0x10008002, 0x40080100, 0x04020100, 0x02040404, 0x82082081,
|
||||
0x84210420, 0x84442210, 0x44888888, 0x24491224, 0x4a492489, 0x94949492, 0x54a54a52, 0xaa9552a9,
|
||||
0xaaaaaaaa, 0xaad55aaa, 0xb5ad6ad5, 0xd6dadad6, 0xb6db6db6, 0xeddb76dd, 0x7777776e, 0x7bddeef7,
|
||||
0xbef7bdf7, 0xdfbefbef, 0xfbfbf7ef, 0xdfeff7fb, 0xbffbff7f, 0xfefffbff, 0xffbfffbf, 0xfdffff7f,
|
||||
0xffffdfff, 0xffeffffe, 0xfbfffeff, 0xf7fff7ff, 0xff7ffdff, 0xfdffbff7, 0xbfbfdff7, 0xdfbfbfbf,
|
||||
0xdf7efbef, 0xdef7defb, 0xddeef7bb, 0xeddddddd, 0x6edbb76e, 0xdb6db6db, 0xb6b6b6b6, 0x56ad6ad6,
|
||||
0xaab556ab, 0xaa5556aa, 0xaa554aaa, 0x94a52a54, 0x92525252, 0x12492494, 0x48912249, 0x22222224,
|
||||
0x10884422, 0x08210842, 0x02081042, 0x40404081, 0x01008040, 0x00801004, 0x40010008, 0x20002000,
|
||||
0x00008000, 0x00400004, 0x20000200, 0x00010000, 0x00040004, 0x10008002, 0x40080100, 0x04020100,
|
||||
0x02040404, 0x82082081, 0x84210420, 0x84442210, 0x44888888, 0x24491224, 0x4a492489, 0x94949492,
|
||||
0x54a54a52, 0xaa9552a9, 0xaaaaaaaa, 0xaad55aaa, 0xb5ad6ad5, 0xd6dadad6, 0xb6db6db6, 0xeddb76dd,
|
||||
0x7777776e, 0x7bddeef7, 0xbef7bdf7, 0xdfbefbef, 0xfbfbf7ef, 0xdfeff7fb, 0xbffbff7f, 0xfefffbff,
|
||||
0xffbfffbf, 0xfdffff7f, 0xffffdfff, 0xffeffffe, 0xfbfffeff, 0xf7fff7ff, 0xff7ffdff, 0xfdffbff7,
|
||||
0xbfbfdff7, 0xdfbfbfbf, 0xdf7efbef, 0xdef7defb, 0xddeef7bb, 0xeddddddd, 0x6edbb76e, 0xdb6db6db,
|
||||
0xb6b6b6b6, 0x56ad6ad6, 0xaab556ab, 0xaa5556aa, 0xaa554aaa, 0x94a52a54, 0x92525252, 0x12492494,
|
||||
0x48912249,
|
||||
};
|
||||
|
||||
/* sine table for delta sigma modulation, 2200Hz */
|
||||
static const uint32_t space_tab[SPACE_TAB_LEN] = {
|
||||
0x10000200, 0x10002000, 0x20100200, 0x20404040, 0x44108208, 0x11111108, 0x24924489, 0xa9494949,
|
||||
0x5552aa54, 0x55aad555, 0x6dadad6b, 0xb76dbb6d, 0x77bbbbbb, 0xfbefbdef, 0xbfdfbf7e, 0xbffbff7f,
|
||||
0xf7fff7ff, 0xffffdfff, 0xffeffffe, 0xffbfffbf, 0xfdff7ff7, 0xfbf7f7fb, 0xef7bef7e, 0xbbbbbbbd,
|
||||
0x6db76ddb, 0xad6b5b6b, 0x5556aad5, 0x54aa5555, 0x24a4a52a, 0x12449249, 0x21110911, 0x10420842,
|
||||
0x02020408, 0x00801004, 0x00040008, 0x00400008, 0x10000200, 0x10002000, 0x20100200, 0x20404040,
|
||||
0x44108208, 0x11111108, 0x24924489, 0xa9494949, 0x5552aa54, 0x55aad555, 0x6dadad6b, 0xb76dbb6d,
|
||||
0x77bbbbbb, 0xfbefbdef, 0xbfdfbf7e, 0xbffbff7f, 0xf7fff7ff, 0xffffdfff, 0xffeffffe, 0xffbfffbf,
|
||||
0xfdff7ff7, 0xfbf7f7fb, 0xef7bef7e, 0xbbbbbbbd, 0x6db76ddb, 0xad6b5b6b, 0x5556aad5, 0x54aa5555,
|
||||
0x24a4a52a, 0x12449249, 0x21110911, 0x10420842, 0x02020408, 0x00801004, 0x00040008, 0x00400008,
|
||||
0x10000200, 0x10002000, 0x20100200, 0x20404040, 0x44108208, 0x11111108, 0x24924489, 0xa9494949,
|
||||
0x5552aa54, 0x55aad555, 0x6dadad6b, 0xb76dbb6d, 0x77bbbbbb, 0xfbefbdef, 0xbfdfbf7e, 0xbffbff7f,
|
||||
0xf7fff7ff, 0xffffdfff, 0xffeffffe, 0xffbfffbf, 0xfdff7ff7, 0xfbf7f7fb, 0xef7bef7e, 0xbbbbbbbd,
|
||||
};
|
||||
|
||||
/* sine table for different phase */
|
||||
static const uint32_t *phase_tab[2][PHASE_CYCLE] = {
|
||||
{ &space_tab[0], &space_tab[6], &space_tab[12], &space_tab[18], &space_tab[24], &space_tab[30], },
|
||||
{ &mark_tab[0], &mark_tab[11], &mark_tab[22], &mark_tab[33], &mark_tab[44], &mark_tab[55], },
|
||||
};
|
Ładowanie…
Reference in New Issue