Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:3110d82c59ff, committed 2022-11-15
- Comitter:
- andrewcrussell
- Date:
- Tue Nov 15 11:32:21 2022 +0000
- Commit message:
- Apple final build Nov 15 2022
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Pindef1114.h Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,48 @@ +/************************************ Pinfef1114.h *******************************/ +/****************** for the RC5 preamplifier copntroller program ****************/ +DigitalOut FWD1(dp1); // these are the motor 'H' bridge drive signals +DigitalOut REV1(dp2); // when the volume controll motor is not being driven + // they are all OFF + +DigitalOut muteout(dp13); // drives the mute relay via a mosfet or transistor +//DigitalOut muteind(dp18); +InterruptIn mute_int(dp11); // mute p/button interrupt +DigitalIn mute(dp11); // mute input from associated pushbutton + +DigitalOut stby_pa(dp25); // power amplifier standby control which follows the premap + // but with suitable delays + +InterruptIn rc5int(dp17); // this is the R/C interrupt triggered by the IRx data out +DigitalIn rc5dat(dp17); // data is read in from here - its coming from the IRx data out + + +InterruptIn select_int(dp28); // select rotary encoder interrupt - we use the 'A' O/P to generate the interrupt +DigitalIn sela(dp28); // select input rotary enc input A +DigitalIn selb(dp27); // select input rotary enc input B + +DigitalIn stdby(dp26); // standby function p/button input +InterruptIn stdby_int(dp26); // standby p/button interrupt in + + +//InterruptIn tone_pb(dp15); +//DigitalIn tone(dp15); +//DigitalOut tone(dp25); // can only be turned on and off at this stage by the r/control + +DigitalOut muteLED (dp14); //illumionates whn output is muted +DigitalIn recloop_in(dp14); // record loop p/button input +DigitalOut recloop_out(dp16); // drives record loop LED +DigitalOut recloop_rly(dp10); + +BusOut select_drv(dp11, dp4, dp5, dp6, dp9, dp10); //these are the select relay drivers +// note that we do not explicitly define the input select output ports because we just move the active +// output port bit around in a continuos loop with each depress of the select button. Drive the associated +// input relays via a mosfet or transistor + +// DigitalOut myled(LED1); // for test purposes only - on the mbed module - comment out when not used +// DigitalOut myled2(LED2); +// DigitalOut sync(p29); //this is a sync pin that is toggled during IR read - used for debug only + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apple_codes.h Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,40 @@ +/********************************* RC5 control codes ******************************/ +// The Philips RC5 coce consists of 14 bits delivered in bi-phase Manchester encoding from +// an IR LED on the remote. This is picked up by a detector (e.g. a Vishay TSOP3741) which +// outputs the demodulated bit stream as follows:- +// First 2 bits are start bits - allow the detector AGC to stabilize and trigger decoding process +// Third bit is the toggle bit - it remains at the same logic level as long as a key is depressed +// and will change to the alternate state when the key is un/re-depressed or when a different +// key is depressed +// Bits 4~8 are the address bits and determine which piece of equipment is being controlled +// Bits 9~14 are the command bits +// As long as a key is depressed, the 14 bits will be sent by the remote controller in sequential +// blocks with a 120ms delay between subsequent block transmissions +// See http://en.wikipedia.org/wiki/RC-5 for the codes + +// 0-9 NUMERIC KEYS 0 - 9 - not used in this implementation + +// unused commands and addresses have been commented out - simply un-comment them to use them +// but note that if you do this, you will have to decode them, otherwise they will just fall through +// and be ignored by the decoder. Only the ones un-commented out below are active in V1.0 +// Note you will also need to write the associated command processor functions + +#define STANDBY 378 // toggle power ON and OFF +#define MUTE 442 // toggle output signal on and off +#define VUP 464 +#define VDOWN 432 +#define SELECT_R 480 // rotates input through inputs - must depress and then release each time +#define SELECT_L 272 // rotates input through inputs - must depress and then release each time +#define PREAMP 479 // this is the system code identifying an Apple Remote + + + + + + + + + + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Tue Nov 15 11:32:21 2022 +0000
@@ -0,0 +1,540 @@
+//This is the reference version
+
+
+/****************************** Apple TV Remote Decoder and Preamp Controller V1.0 *************************/
+/* Andrew C. Russell (c) August 2022 */
+/* This Apple TV Remote decoder works by reading in the IR stream from one of the serial port lines */
+/* and saving the incoming stream into an array called stream, after which it is decoded and */
+/* the command executed. */
+
+/* The following audio preamplifier facilities are catered for:- */
+/* 1. Manual/Remote volume control adjustment via ALPS RK27 motorized potentiometer */
+/* 2. Input select via rotary encoder */
+/* 3. Output mute via push button actuation */
+/* 4. Record loop via push button actuation */
+/* 5. Power ON output to drive the /standby input of a system power supply */
+/* Facilities 1,2,3 and 5 are supported by an Apple TV remote */
+/* The controller pin definitions are set in Pindef1114.h file. */
+
+
+// UPDATE 26 July 2018: tone functionality removed. The associated pin (dp25) has been sequestrated
+// for the standby output to drive a power amplifier. Pin 8 on J2 (Controller board)
+
+#include "mbed.h"
+#include "apple_codes.h" // RC code definitions - in this case for Apple TV Remote
+#include "Pindef1114.h" // all microcontroller I/O pin assignments defined here
+
+#define TRUE 1
+#define FALSE 0
+#define HIGH 1
+#define LOW 0
+#define tick 280 // quarter bit time in us
+#define tock 1120 // one bit time in us
+#define VUP_timeout 45 // defines max number of R/C cycles before the vol ctrl mtr drive stops
+#define VDWN_timeout 45 // as above but for volume decrease
+// Needed to ensure the motor is not burnt out
+#define DEBOUNCE 20000 // this is the switch debounce time
+
+// PHONO_ 1 // these are the input assignments written out
+// CD 2 // on select_out - see thePindef1114.h file for details
+// TUN 4
+// MSERV 8
+// AUX 16
+// RECORDER 32
+/******************************************************************************************/
+//DigitalOut FWD1(dp1); // these are the motor 'H' bridge drive signals
+//DigitalOut REV1(dp2); // when the volume controll motor is not being driven
+ // they are all OFF
+
+//DigitalOut muteout(dp13); // drives the mute relay via a mosfet or transistor
+//DigitalOut muteLED(dp14);
+//InterruptIn mute_int(dp11); // mute p/button interrupt
+//DigitalIn mute(dp11); // mute input from associated pushbutton
+
+//DigitalOut stby_pa(dp25); // power amplifier standby control which follows the premap
+ // but with suitable delays
+
+//InterruptIn rc5int(dp17); // this is the R/C interrupt triggered by the IRx data out
+//DigitalIn rc5dat(dp17); // data is read in from here - its coming from the IRx data out
+
+
+//InterruptIn select_int(dp28); // select rotary encoder interrupt - we use the 'A' O/P to generate the interrupt
+//DigitalIn sela(dp28); // select input rotary enc input A
+//DigitalIn selb(dp27); // select input rotary enc input B
+
+//DigitalIn stdby(dp26); // standby function p/button input
+//InterruptIn stdby_int(dp26); // standby p/button interrupt in
+
+
+//InterruptIn tone_pb(dp15);
+//DigitalIn tone(dp15);
+//DigitalOut tone(dp25); // can only be turned on and off at this stage by the r/control
+
+//InterruptIn recloop_int(dp14); //record loop interrupt
+//DigitalIn recloop_in(dp14); // record loop p/button input
+//DigitalOut recloop_out(dp16); // drives record loop LED
+//DigitalOut recloop_rly(dp10);
+
+//BusOut select_drv(dp11,dp4, dp5, dp6, dp9, dp10); //these are the select relay drivers
+
+/*******************************************************************************************/
+
+
+int startbit;
+int toggle; // this is the 3rd bit position in the input stream and checks for
+// subsequent button depresses from the r/control
+int toggle1; // temorary storage in the volume UP and volume DOWN functions
+int toggle2; // temprary storage of the PB in the mute function
+int toggle3; // temp storage for the r/control tone in-out function
+int standby;
+int command = 0;
+int vendor_id = 0;
+int pair_command = 0;
+int address = 0;
+int stop_bit = 0;
+int recloop_status = 0;
+int FLAG1; // this is used in the remote control input processing
+int FLAG2; // this is used in the select input processing
+int FLAG3; // this is for the mute pushbutton
+int FLAG4; // this is for the standby pushbutton
+// int FLAG5; // this is the recloop flag
+int RCFLAG = FALSE; // used to determine if the select command came via R/C
+int REPEATFLAG; // repaet command flag used for volume control
+//int FLAGVOLUP;
+//int FLAGVOLDWN;
+//int FLAG7 = FALSE; // thyis flag is set to TRUE if recloop is active
+int standbyflag; // used to save the standby condition
+int RECLOOP1 = 16; // this is the bus address 1 before the Recorder
+int RECLOOP2 = 32; // this is the bus address for the Recorder input
+// and is used in the recloop service routine
+int muteflag = FALSE; // use to control mute and mute indicatoe independently
+//int recloop_status = 32; // this is the initial value. This variable is used
+// in the select_out routine to indicate when the
+// input select should wrap around dependent upon
+// whether the record loop has been activated.
+int relay;
+int key_press = 1; // keeps track of key presses
+int REPEAT = 511; // this is the repeat code for volup and voldown
+int COMSTORE = 0; // store the previous command
+
+// delcarations below are all for the input select proceses
+int select = 0;
+int select_save = 2; // we save the status of select drive here. Initial setting is for CD
+int select_rot; // rotary encoder pulse counter
+
+// declare function prototypes here
+void select_out (void); // writes selected input out to the select_drv bus
+void select_isr(void);
+void rc5isr(void); // RC5 ISR for remote control
+void mute_isr(void);
+void mute_sel(void); //mutes select relays for a few ms during select
+//void recloop_isr(void);
+void standby_out(void);
+
+/****************************** volume increase ***********************************/
+void vol_up (void)
+{
+ if ((standbyflag == TRUE) && (key_press < VUP_timeout)) {
+ FWD1 = HIGH;
+ wait_us(100000); //drive the motors for a short while
+ }
+ FWD1 = LOW;
+
+ // }
+ // if (toggle1 != toggle) {
+ // key_press = 0; // user released the button, so reset counter
+ // } else if (toggle1 == toggle) {
+ // key_press++; // button remained depressed, so increment counter
+ //}
+ //// toggle1 = toggle;
+ wait_us(1000);
+}
+
+/******************************* volume decrease **********************************/
+void vol_dwn (void)
+{
+ if ((standbyflag == TRUE) && (key_press < VDWN_timeout)) {
+ REV1 = HIGH;
+ wait_us(1000); //drive the motors for a short while
+ }
+ REV1 = LOW;
+ // }
+ // if (toggle1 != toggle) {
+ // key_press = 0; // user released the button, so reset counter
+ // } else if (toggle1 == toggle) {
+ // key_press++; // button remained depressed, so increment counter
+ // }
+ // toggle1 = toggle;
+ wait_us(1000);
+}
+
+/********************************** stdby_isr *************************************/
+void stdby_isr(void)
+{
+ FLAG4 = TRUE;
+}
+
+/*********************************** standby **************************************/
+/* this will require supporting hardware functionality to power down the */
+/* analog board, LED's etc. Best option here is to use regulators with a */
+/* shutdown option. for now, all the LED's are just turned off */
+/* and input relays and mute relayes disabled. */
+
+void standby_out(void) // both p/button and R/C come in here
+{
+ __disable_irq();
+ stdby_int.fall(NULL); // on first power up cycle NO interrupts are accepted
+ wait_us(DEBOUNCE); // a very simple debounce
+ do { // that waits for the depressed button to be released
+ continue; //(1);a
+ } while (stdby != 1);
+
+ if (standbyflag == TRUE) { // was ON so now turn it OFF
+ stby_pa = HIGH; // turn the trigger output OFF
+ wait_us(1000000); //make sure power amp has powered down
+ muteLED = HIGH;
+ muteout = LOW; // now mute the preamp
+ wait_us(3000000);
+ // turn off all interrupts except the standby and rc5int
+ select_int.fall(NULL);
+ select_save = select_drv; // save the status of select_drv
+ select_drv = 0; // all input select relays are OFF
+ standbyflag = FALSE;
+ muteflag = FALSE;
+ muteLED = LOW;
+ }
+
+
+ else if (standbyflag == FALSE) {// was OFF so we will turn it ON
+
+ muteLED = HIGH; // turn the mute indicator ON
+ rc5int.rise(&rc5isr); // trigger int on rising edge - go service it at rc5dat
+ select_int.fall(&select_isr); // input from rotary encoder or input select
+ wait_us(100000);
+ select_drv = select_save; // recall the input select setting and write to output
+ wait_us(2000000); // let things settle a bit
+ muteout = HIGH; // enable output
+ muteflag = FALSE;
+ muteLED = LOW; // turn the mute indicator OFF
+ standbyflag = TRUE;
+ wait_us(3000000); // make sure preamp has settled before powering power amp ON
+ stby_pa = LOW; // now power up the amplifier
+ }
+ wait_us(500000); // let things settle a bit
+ __enable_irq();
+ stdby_int.fall(&stdby_isr); // re-enable the standby interrupt
+
+}
+
+/************************************** mute ************************************/
+void mute_out()
+{
+
+ if (muteflag == FALSE) { // mute was inactive so it will now get activated
+ wait_us(100000);
+ muteout = LOW;
+ muteLED = HIGH;
+ muteflag = TRUE; // indicate its been activated
+ }
+
+ else if (muteflag == TRUE) { //it was active, so it must be deactivated here
+ wait_us(100000);
+ muteout = HIGH;
+ muteLED = LOW;
+ muteflag = FALSE;
+ }
+
+ wait_us(800000); // make sure relay state is settled
+
+}
+
+/************************************ rc5isr **************************************/
+/* Interrupt triggered by a rising edge on p21 which is R/C data in */
+
+void rc5isr(void)
+{
+ FLAG1 = TRUE;
+ RCFLAG = TRUE;
+
+}
+
+/******************* save bit stream from remote controller ***********************/
+/* This function reads the input data on pin rc5dat at 1120us ('tock')intervals */
+/* and saves the data into an array stream[i]. */
+
+void save_stream(void)
+{
+ if (RCFLAG == TRUE) {
+ wait_us(13500); // this is the AGC header - ignore
+ }
+
+ bool stream[32];// the array is initialized each time it is used and is local only
+ int bitloop; // number of bit positions
+ int i = 0; // counter
+ int k = 0; // temp storage
+ vendor_id = 0;
+ pair_command = 0;
+ address = 0;
+ command = 0;
+ stop_bit = 0; //must always return a 1 to be valid, so reset it
+ wait_us(tick); // locate read point in middle of 1st half bit time of the 1st start bit
+
+ for (bitloop = 0; bitloop <32; bitloop ++) {
+
+ stream[bitloop] = rc5dat; //read the data and save it to array position [i]
+// bitstream = !bitstream; // RC bitstream moinitor on pin 14
+ if (rc5dat == HIGH) {
+ wait_us(tock);
+ }
+
+ wait_us(tock); //wait here until ready to read the next bit in
+ } // now have 31 bits loaded into stream[i]
+
+ /* now put data in the array into the start, toggle, address and command variables - array counts from stream[0] */
+
+ for (i=0; i<11; i++) { // first 11 bit positions are vendor ID - always 043f for Apple; use for error checking later
+
+ k = stream[i]; // k will hold the vendor ID
+ vendor_id = (vendor_id << 1);
+ vendor_id = vendor_id|k;
+
+ }
+
+ for (i = 11; i <16; i++) { // command or pair
+ k = stream[i];
+ pair_command = (pair_command << 1);
+ pair_command = pair_command|k;
+ }
+
+ for (i = 16; i <25; i++) { // device pairing address
+ k = stream[i];
+ address = (address << 1);
+ address = address|k;
+ }
+
+
+ for (i = 25; i <31; i++) { // bit positions 25 to 30 are the command - 7 bit positions
+ k = stream[i];
+ command = (command << 1);
+ command = command|k;
+ }
+ stop_bit = stream[31];
+
+ // printf("\n vendor_id = %d pair_command = %d address = %d command = %d stop_bit = %d \r", vendor_id, pair_command, address, command, stop_bit);
+}
+
+/********************************* process_stream() *******************************/
+/* handles commands coming in from the remote controller only */
+
+void process_stream (void)
+{
+ if ((RCFLAG == TRUE) && ((vendor_id == 479) || (vendor_id == 2047)) ) {
+ // basic error checking - must be preamp + startbit ok to get executed otherwise skip completly
+
+ if (address == REPEAT) {
+ address = COMSTORE; }
+
+
+ switch (address) {
+
+ case VUP:
+ if (standbyflag == TRUE) {
+ vol_up();}
+ //FLAGVOLUP = TRUE;
+ break;
+
+ case VDOWN:
+ if (standbyflag == TRUE) {
+ vol_dwn(); }
+ // FLAGVOLDWN = TRUE;
+ break;
+
+ case MUTE:
+ if (standbyflag == TRUE) {mute_out();}
+ break;
+
+ case SELECT_R:
+ if (standbyflag == TRUE) { select_out();}
+ wait_us(300000);
+ break;
+
+ case SELECT_L:
+ if (standbyflag == TRUE) { select_out();}
+ wait_us(300000);
+ break;
+
+ case STANDBY:
+ standby_out();
+ break;
+
+ }
+COMSTORE = address; // save the just execued command
+
+ }
+ RCFLAG = FALSE;
+
+}
+/*********************************** select_isr ***********************************/
+
+void select_isr(void)
+{
+ FLAG2 = TRUE;
+}
+
+/****************************** mute inter select*********************************/
+
+void mute_sel(void)
+{
+ select_drv = 0;
+ wait_us(2000);
+}
+
+/********************************* select_process *********************************/
+/* Used for selecting the input source. This function is used by the */
+/* rotary encoder only */
+
+void select_process(void)
+{
+
+ if (RCFLAG == FALSE) { // if used R/C skip completely - extra safety check
+ wait_us(5000); // debounce - very short for the rotary encoder
+ select = 0; // flush select
+
+ select = (select | sela) <<1; // read the two port lines associated with the select rotary encoder
+ select = (select | selb);
+
+
+ switch (select) {
+ case 1: // select encoder is being rotated CW so increment select_rot
+ select_rot <<= 1;
+ if (select_rot > 32 ) {
+ select_rot = 1; // wrap around to 1
+ }
+
+ break;
+
+ case 0:
+ select_rot >>= 1; // encoder is being rotated CCW so decrement select_rot
+ if (select_rot < 1) {
+ select_rot = 32; //wrap around to 32
+ }
+
+ break;
+
+ case 2:
+ break; // indeterminate fall through values - ignore
+ case 3:
+ break; // and do not change the output
+ }
+ }
+
+ select_drv = select_rot; // write the value out to the bus
+
+// printf("\n RCFLAG %d select_rot %d \r", RCFLAG, select_rot);
+}
+
+
+
+
+/********************************* select_out *********************************/
+// this is only used by the IR remote
+
+void select_out (void)
+{
+
+ if (address == SELECT_L) {
+ select_rot >>= 1;
+ if (select_rot <1) {
+ select_rot = 32;
+ }
+ }
+
+
+ if (address == SELECT_R) {
+ select_rot <<= 1;
+ if (select_rot >32) {
+ select_rot = 1;
+ }
+
+ }
+
+ select_drv = select_rot; //write the selection out to the bus.
+
+// printf("\n select_rot = %d select_drv = %d\r", select_rot, select_drv);
+
+}
+
+/************************************ main() ***************************************/
+int main(void)
+{
+ // Serial pc(USBTX, USBRX);
+ __disable_irq(); // just to make sure we can set up correctly without problems
+ stby_pa = HIGH; // make sure the power aamp is OFF
+ // make sure the power amp is OFF via the trigger output
+ muteout = LOW; //make sure the outputis muted from the get go
+ muteLED = HIGH; //mute LED must be ON - power up preamble
+ select_drv = 0;
+ // bitstream = LOW; // make sure the bitream monitor is LOW
+ rc5dat.mode(PullUp); // pin 17
+ sela.mode(PullUp); // pin 28
+ selb.mode(PullUp); // pin 27
+ stdby.mode(PullUp); // pin 26
+ //recloop_in.mode(PullUp); // pin 14
+
+ wait_us(200000);
+ FLAG1 = FALSE;
+ FLAG2 = FALSE;
+ FWD1=0; //make sure the volume control motor is OFF
+ REV1=0;
+
+ // set up the ISR's that will be used
+ rc5int.fall(&rc5isr); // trigger int on rising edge - go service it at rc5dat
+ select_int.fall(&select_isr); // input from rotary encoder or input select
+ stdby_int.fall(&stdby_isr); // the system power/standby switch
+
+ //now disable them, leaving only the stand by p/button and rc5int interrupts active
+ select_int.fall(NULL);
+
+ standbyflag = TRUE; // preamp will be set-up first time for OFF
+ standby_out(); // set system up
+ standbyflag = FALSE;
+ select_save = 2;
+ select_rot = select_save; // CD will be selected when power is first turned on
+ wait_us(1000000);
+ muteLED = LOW;
+ muteflag = FALSE;
+ __enable_irq();
+
+// all ready and in standby from this point forward
+
+LOOP: // this is the main operating loop
+
+ __WFI(); // wait here until interrupt
+
+
+ if (FLAG1 == TRUE) { // FLAG1 indicates remote control was used
+ save_stream();
+ process_stream();
+
+ FLAG1 = FALSE;
+ }
+
+ if (FLAG2 == TRUE) {
+ select_process(); //select process
+ FLAG2 = FALSE;
+ }
+
+
+ if (FLAG4 == TRUE) { // standby ON/OFF
+ standby_out();
+ FLAG4 = FALSE;
+ }
+
+
+ goto LOOP;
+
+}
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Nov 15 11:32:21 2022 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400 \ No newline at end of file