TASCAM Sound Recorder (Part 4)

Part 1, 2, 3, 4

And here is the driver code. Nothing exceptional just plain good’ol arduino code. Check theĀ writeByte function which contains few tricks and optimizations that are mandatory to achieve a proper timing. Ultimately this code contains a pretty versatile bit-bang UART writer that you may want to reuse in various applications.

Enter the DR-40 commands through the key board of the console using the abbreviations from the commands:

  • ‘p’: PLAY
  • ‘s’: STOP
  • ‘r’: RECORD
  • ‘f’: FORWARD
  • ‘b’: BACK
  • ‘m’: MARK
  • ‘1’: F1
  • ‘2’: F2
  • ‘3’: F3
  • ‘4’: F4
uint8_t _TxMask;
uint8_t _TxMaskBar;
volatile uint8_t *_TxPort; 
uint16_t _timeInterval;
bool _invert;
bool _parity;
#define ONE_MILLION 1000000UL
    
#define STOP 		0x08
#define PLAY 		0x09
#define RECORD 		0x0B
#define FORWARD 	0x0E
#define BACK 		0x0F
#define MARK 		0x18
#define F1 			0x1C
#define F2 			0x1D
#define F3 			0x1E
#define F4 			0x1F

#define KEY_PRESS	0x40
#define KEY_DOWN	0x60
#define KEY_UP		0x00

#define PAR_NONE	0x00
#define PAR_EVEN	0x01
#define PAR_ODD		0x02

/*
Initialize communication port 
Any pin on any port can be used
Baud rate goes up to 57600 
Parity may be none (0), odd (1) or even (2)
Data may be inverted or not (flip mark and spaces)
*/
void begin(volatile uint8_t *TxPort, uint8_t TxPin, uint32_t baudRate = 9600, uint8_t parity = PAR_NONE, bool invert = true)
{
    /* Record global variables */
    _invert = invert;
    _parity = parity;
    /* Transmit port */
    _TxPort = TxPort;
    /* Transmit pin */
    _TxMask = (0x01 << TxPin);
    _TxMaskBar = ~_TxMask;
    /* Make TxPin an output pin */
    *(_TxPort - 1) |= _TxMask; 	
    /* Set idle mode */
    if  (!_invert) 
    {
        *(_TxPort) |= _TxMask;
    } 
    else 
    {
        *(_TxPort) &= _TxMaskBar;
    }
    /* Set bits intervals  in us */
    _timeInterval = (ONE_MILLION / baudRate);
}


/* 
Write byte on serial port
global variables in use:
    _parity
    _invert
    _TxPort
    _TxMask
    _TxMaskBar
    _timeInterval

idle
-----------     ---     ---     ---     ---    ---- --- ----   1 mark
           |Sta| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |Par|Stp|
            ---     ---     ---     ---     --- ---           0 space/break
*/
void writeByte(const uint8_t data) 
{
    uint32_t now;
    uint16_t compositeBits = 0x00; /* Map data bits */
    /* compositeBits content: 76543210 */
    compositeBits |= data; /* Map data bits */
    uint8_t bits = 8;
    if (_parity != PAR_NONE)
    {
        bool dataParity = parity(data);
        /* Append a mark as appropriate */
        if (((_parity == PAR_EVEN) && dataParity) || ((_parity == PAR_ODD) && !dataParity))
        {
            /* compositeBits content: p76543210 */
            compositeBits |= (0x01 << bits);  /* Map parity bit */
        }
        bits += 1; /* Actually 9 bits */
    }
    /* compositeBits content: Sp76543210 or S76543210*/
    compositeBits |= (0x01 << bits);  /* Map stop bit (mark) */	
    /* compositeBits content: Sp76543210s or S76543210s */
    compositeBits <<= 1; /* Shift bits for start inclusion (space) */
    bits += 2;
    if (_invert)
    {
        compositeBits= ~compositeBits;
    }
    uint32_t lastTick = micros(); /* Record start time of bits transfer */
    /* Transfer composite bits starting from lower bits */
    for (uint8_t i = 0; i < bits; i++) 
    {
        uint8_t bitValue = (compositeBits & 0x01); /* Extract lower bit value */
        if  (bitValue) 
        {
            *(_TxPort) |= _TxMask;
        } 
        else 
        {
            *(_TxPort) &= _TxMaskBar;
        }
        compositeBits >>= 1; /* Shift bits */
        while((micros() - lastTick) < _timeInterval);
        lastTick += _timeInterval; /* Set next bit release time */
    }
}

/*
Send function key 
*/
void sendKey(uint8_t function)
{
    writeByte(function | KEY_PRESS);
    delay(150);
    writeByte(function | KEY_UP);
}

/* 
Computes the parity from a value. The function returns a true for an odd number
of bits and a false for an even number of bits.
*/
bool parity(uint8_t n) 
{ 
    bool parity = 0; 
    while (n) 
    { 
        parity = !parity; 
        n = (n & (n - 1)); 
    }         
    return(parity); 
} 

void setup()
{
    /* Configure serial port using default parameters */
    begin(&PORTB, PINB0, 9600, PAR_EVEN, true);
    delay(500);
    Serial.begin(115200);
}

void loop()
{
    /* Listen to incoming bytes from the console */
    if (Serial.available() > 0)
    {
        char inputByte = (char)Serial.read();
        switch(inputByte)
        {
            case 'p': sendKey(PLAY); break;
            case 's': sendKey(STOP); break;
            case 'r': sendKey(RECORD); break;
            case 'f': sendKey(FORWARD); break;
            case 'b': sendKey(BACK); break;
            case 'm': sendKey(MARK); break;
            case '1': sendKey(F1); break;
            case '2': sendKey(F2); break;
            case '3': sendKey(F3); break;
            case '4': sendKey(F4); break;
        }
    }
    delay(10);
}

 

 

Leave a Reply

You must be logged in to post a comment.