Advertisement
samtal

Maple Dual Reg ADC

Oct 3rd, 2011
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.49 KB | None | 0 0
  1. /**
  2.  **********************************************************************************************
  3.  * @file    DualRegSample.pde
  4.  * @author  Samtal
  5.  * @version V1.1.0
  6.  * @date    27-SEP-2011   (Original 27 AUG 2011)
  7.  * @brief   For Maple r5, IDE 0.0.12 Main program body
  8.  *********************************************************************************
  9.  * PLEASE READ THESE INSTRUCTIONS
  10.  * This program demonstrates the implementation of the STM32F10X Dual-Simultaneous
  11.  * ADC on the Maple r5, using the Maple IDE 0.0.11.
  12.  * Some functions that were missing in the original libMaple adc.h/adc.c where
  13.  * added as indicated and are in the included dadc.h which can be included with
  14.  * the adc.h or fully replace it.
  15.  * Each such command can be replaced by its adjacent direct registery access
  16.  * command by un-commenting.
  17.  * The program includes several debugging, training and demonstration options.
  18.  *
  19.  * For testing and demo purposes, a digital output channel can be toggled on / off
  20.  * to supply 3.33V that can be divided by one 1 KOhm pot. connected from the output
  21.  * pin (23) to input chan 15 (pin 20) and six 1 KOhm resistors between channels
  22.  * 15-10 (pins (20)-1K-(19)-1K-(18)-1K-(17)-1K-(16)-1K-(15)-1K-(GND).
  23.  * Adjust the pot to supply 3V to chan 15 (pin 20), which will yield
  24.  * 0.5V,1V,1.5V,2V,2.5V,3V to the channels.
  25.  * To test voltage existence, connect pin 23 to pin 26 (Dig Input), and the program
  26.  * will show power on / off.
  27.  * The program is set to load program and read data by SerialUSB.
  28.  * Although all can be done by SerialUSB , I strongly recommend to use another serial
  29.  * ports for data display (like Serial1), which will enable catch output before the
  30.  * USB port is returned from programming mode. Change SetrialUSB to Serial1 and initialize the port.
  31.  ***************************************************************************************************
  32.  * Real-time input parameters:
  33.  * 'r' to display the relevant registers, stop by 'R'.
  34.  * 'v' to display data in real volts, stop by 'V'.
  35.  * 'b' to display the adc raw data in binary to decimal format. Stop by 'B'.
  36.  * 't' to toggle on/off output pin 23 (tied to input pin 27 (an. chan. 8)) and pin 26 (dig in)
  37.  *
  38.  * Notes: This sample enables 6 X 2 Analog In channels in SQR3 only, out of which any even pair number  
  39.  * can be used (the param 'adc_length' in channel pairs).
  40.  */
  41.  
  42. #include "stdlib.h"      //Must be included explicitly for proper data printing.
  43. //#include "dadc.h"      // Optional. Read Instructions !!  USE ONLY IF DADC.H PRESENT !!
  44. #include "dma.h"
  45.  
  46. uint8 adc_length=4;     //The number of channels to be converted per ADC channel
  47. int16 adc1_data;        //Temporary binary data
  48. int16 adc2_data;        //Temporary binary data
  49. uint32 adc_sequence=0;  //Temporary
  50. boolean dispReg=false;
  51. boolean dispVolts=true;
  52. boolean dispBin=false;
  53. float adc1_Vdata;
  54. float adc2_Vdata;
  55. float voltsConvert=3.350; //Conversion to voltage. Use for fine-tuning calibration.
  56. uint32 irq_fired = 0;    //Optional for user function.
  57. uint32 rawDataArray[6];  //The dma temporary data array.
  58. uint8 ADC1_Sequence[]={  /*The ADC1 channels sequence, left to right*/
  59.   8,10,12,14,0,0}; /* Set the sequence 1-6 for SQR3 (left will be first). Must top up to all 6 channels with zeros  */
  60. uint8 ADC2_Sequence[]={  /*The ADC2 channels sequence, left to right*/
  61.   9,11,13,15,0,0};
  62. uint8 i;
  63.  
  64. void setup()
  65.  
  66. {
  67. //  Serial1.begin(115200);     //Optional, if Serial1 is used.
  68.  
  69.  welcome_message();
  70.  
  71.   /* Set the relevant ADC pins to analog in */
  72.   pinMode(27, INPUT_ANALOG);  //Pins 27,28, ADC channels 8,9
  73.   pinMode(28, INPUT_ANALOG);
  74.   for (int k=15;k<21;k++)    ////Pins 15-20, ADC channels 10-15
  75.   {
  76.     pinMode(k, INPUT_ANALOG);
  77.   }
  78.   /* For testing:*/
  79.   pinMode(23, OUTPUT); //Connect pin 23 via voltage divider to the analog input pins, Set pin 23 as output.
  80.   togglePin(23); //Initially, toggle pin 23 ON. To change state, send 't'.
  81.   pinMode(26,INPUT); //Connected to output pin 23. Used to test if the output is on or off
  82.  
  83.   adc_init(ADC1);    //rcc_clk_enable(ADC1->clk_id), Must be the first adc command!
  84.   adc_init(ADC2);
  85.  
  86.   adc_enable(ADC1);  //ADC_CR2_ADON_BIT = 1
  87.   adc_enable(ADC2);
  88.  
  89.   adc_calibrate(ADC1);  //Optional
  90.   adc_calibrate(ADC2);
  91.   /*
  92.    * The total conversion time is calculated as follows: Tconv = Sampling time + 12.5 cycles
  93.    * Example, with an ADCCLK = 14 MHz and a sampling time of 1.5 cycles:
  94.    * Tconv = 1.5 + 12.5 = 14 cycles = 1 μs
  95.    */
  96.   adc_set_sample_rate(ADC1, ADC_SMPR_55_5);  // Setting all channels sampling time in cycles:
  97.   adc_set_sample_rate(ADC2, ADC_SMPR_55_5); //1,5;7,5;13,5;28,5;41,5;55,5;71,5;239,5.
  98.  
  99.   /*
  100.    From ST Manual: In dual mode, when configuring conversion to be triggered by an external event,
  101.    the user must set the trigger for the master only and set a software trigger for the slave to
  102.    prevent spurious triggers to start unwanted slave conversion. However, external triggers must be
  103.    enabled on both master and slave ADCs
  104.    */
  105.  
  106.   adc_set_exttrig(ADC1, 1);        //External trigger must be Enabled for both ADC.
  107.   adc_set_exttrig(ADC2, 1);        //External trigger must be Enabled for both ADC.
  108.  
  109.   adc_set_extsel(ADC1,ADC_ADC12_SWSTART);   //External trigger Event, ADC1 only!
  110.  
  111.   /*
  112.    Once the scan bit is set, ADC scans all the channels selected in the ADC_SQRx registers.
  113.    A single conversion is performed for each channel of the group.
  114.    After each end of conversion the next channel of the group is converted AUTOMATICALLY.
  115.    If the DMA bit is set, the direct memory access controller is used to transfer the converted
  116.    data of regular group channels to SRAM after each EOC.
  117.    */
  118.  
  119.   /***SELECT BETWEEN THE FOLLOWING OPTIONS*/  //
  120.   ADC1->regs->CR1 |= 1 << 8;  // Set scan mode  
  121.   ADC2->regs->CR1 |= 1 << 8;  // Set scan mode  
  122.   //scan_mode(ADC1,1);      //USE ONLY WITH DADC.H  (not in adc.h)
  123.   //scan_mode(ADC2,1);      //USE ONLY WITH DADC.H  (not in adc.h)
  124.  
  125.   adc_set_reg_seqlen(ADC1, adc_length);  //The number of channels to be converted.
  126.   adc_set_reg_seqlen(ADC2, adc_length);
  127.   /*
  128.    * calc_adc_sequence(ADCx_Sequence) converts the SQR3 6 channels' (each ADC1 and ADC2) list into
  129.    * a valid 6 X 5=30 bits sequence format. Load the sequence onto one of 3 SQR registers.
  130.    * For more channels, repeat the same for SQR2, SQR1. (For SQR1 4 channels only!)
  131.    */
  132.   ADC1->regs->SQR3 |= calc_adc_sequence(ADC1_Sequence);
  133.   ADC2->regs->SQR3 |= calc_adc_sequence(ADC2_Sequence);
  134.  
  135.   /***SELECT BETWEEN THE FOLLOWING OPTIONS*/  //
  136.   ADC1->regs->CR1 |= 6 << 16;                  //Regular simultaneous mode ADC1 only !!*/
  137.   //set_dual_mode(ADC1,DADC_MODE_6);      // Not in adc files.//USE ONLY WITH DADC.H
  138.  
  139.   /***SELECT BETWEEN THE FOLLOWING OPTIONS*/  //
  140.   ADC1->regs->CR2 |= 1 << 8; //ADC_CR2_DMA_BIT 8=1, Use DMA for adc. ADC1 only.
  141.   //adc_dma_enable(ADC1);  //Not in adc files       //USE ONLY WITH DADC.H
  142.  
  143.   /* Setup of the DMA for the adc data */
  144.   init_dma_xfer();                
  145. }
  146. void init_dma_xfer(void)
  147. {
  148.   dma_init(DMA1);      // MUST initiate before ANY other setting!!!!.dma_init: rcc_clk_enable(dev->clk_id)
  149.  
  150.   dma_setup_transfer
  151.     (
  152.   DMA1,               //dma_device
  153.   DMA_CH1,            //dma_channel
  154.   &ADC1_BASE->DR,     //*peripheral_address,
  155.   DMA_SIZE_32BITS,    //peripheral_size,
  156.   rawDataArray,       //*memory_address, user defined array.
  157.   DMA_SIZE_32BITS,    //memory_size,
  158.   DMA_MINC_MODE       //dma mode, Auto-increment memory address
  159.   );  
  160.  
  161.   dma_set_priority(DMA1, DMA_CH1, DMA_PRIORITY_HIGH);    //Optional
  162.   dma_set_num_transfers(DMA1,DMA_CH1,adc_length);
  163.   dma_attach_interrupt(DMA1, DMA_CH1,end_of_transf_irq);
  164.   dma_enable(DMA1,DMA_CH1);                //CCR1 EN bit 0
  165.   DMA1->regs->CCR1 |= DMA_CIRC_MODE;        //Not in dma files. Set circular mode CCR1 CIRC bit 5
  166.  
  167. } //end init_dma_xfer
  168.  
  169. void end_of_transf_irq(void)     //User function
  170. {  
  171.   irq_fired = true;
  172. }
  173.  
  174. void loop()
  175. {
  176.   //Shows the test voltage state.
  177.   if (digitalRead(26))
  178.   {
  179.     SerialUSB.println("Output ON");
  180.   }
  181.   else
  182.   {
  183.     SerialUSB.println("Output OFF");
  184.   }
  185.  
  186.   /* In SCAN mode, 'software_start' activates an automatic scan conversion and and DMA transfer of ONE dual ADC sequence.
  187.    *  to the defined memory array. For repetitive DMA transfers, the DMA Circular mode must be seleted.
  188.    */
  189.  
  190.   /***SELECT BETWEEN THE FOLLOWING OPTIONS*/  //
  191.   ADC1->regs->CR2 |= 1 << 22;    //software_start(ADC1 only)
  192.   //software_start(ADC1,1); //Not in adc files      //USE ONLY WITH DADC.H
  193.  
  194.   // /* Check DMA1 transfer complete flag */
  195.   while(!(dma_get_isr_bits(DMA1,DMA_CH1)&1))   // Wait on dma transfer complete on channel (DMA_ISR_TCIF1_BIT)
  196.   {
  197.     dma_clear_isr_bits(DMA1,DMA_CH1);  //Global Clear DMA1 channel1 transfer flags */
  198.  
  199.     /***SELECT BETWEEN THE FOLLOWING OPTIONS*/    //
  200.     ADC1->regs->SR |= 1<<1 ;          //Clear the end-of-conversion bit *ADC_SR_EOC_BIT) = 0;
  201.     //end_of_conversion_clear(ADC1);    //Not in adc files. //USE ONLY WITH DADC.H
  202.   }
  203.  
  204.   for (i= 0; i<adc_length;i++)
  205.   {
  206.     adc1_data = (rawDataArray[i] & 0xFFF);        //ADC1 lower 12 bit out of 16 lower bits in 32 bits data register.
  207.     adc2_data = (rawDataArray[i] >>16 & 0xFFF);   //ADC2 lower 12 bit out of upper 16 bits in 32 bits data register.
  208.  
  209.     if (dispReg)       //Display the relevant registries
  210.     {
  211.       print_registers();
  212.     }
  213.     if (dispBin)         //Display the raw data binary converted to decimal format
  214.     {
  215.       SerialUSB.print(ADC1_Sequence[i]);
  216.       SerialUSB.print("\t");
  217.       SerialUSB.print(adc1_data);
  218.       SerialUSB.print("\t");
  219.       SerialUSB.print(ADC2_Sequence[i]);
  220.       SerialUSB.print("\t");
  221.       SerialUSB.println(adc2_data);
  222.     }
  223.  
  224.     if (dispVolts)
  225.     {
  226.       adc1_Vdata=(float(adc1_data)) / 4095 * voltsConvert;
  227.       adc2_Vdata=((float)(adc2_data)) / 4095 * voltsConvert;
  228.  
  229.       SerialUSB.print(ADC1_Sequence[i]);
  230.       SerialUSB.print("\t");
  231.       SerialUSB.print((float)adc1_Vdata,3);
  232.       SerialUSB.print(" V\t\t");
  233.       SerialUSB.print(ADC2_Sequence[i]);
  234.       SerialUSB.print("\t");
  235.       SerialUSB.print((float)adc2_Vdata,3);
  236.       SerialUSB.println(" V\t");
  237.     }
  238.   }
  239.  
  240.   SerialUSB.println();
  241.   SerialUSB.println();
  242.   delay(2000);
  243.  
  244.   while (SerialUSB.available())
  245.   {
  246.     uint8 input = SerialUSB.read();
  247.     SerialUSB.println(input);
  248.  
  249.     switch(input)
  250.     {
  251.     case 'r':
  252.       dispReg=true;
  253.       break;
  254.     case 'R':
  255.       dispReg=false;
  256.       break;
  257.     case 'v':
  258.       dispVolts=true;
  259.       break;
  260.     case 'V':
  261.       dispVolts=false;
  262.       break;
  263.     case 'b':
  264.       dispBin=true;
  265.       break;
  266.     case 'B':
  267.       dispBin=false;
  268.       break;
  269.     case 't':
  270.       togglePin(23);
  271.       break;   //Toggle test voltage   on / off
  272.       case 'd':
  273.        welcome_message();
  274.     default :
  275.       SerialUSB.print("Bad input");
  276.       break;
  277.     }
  278.   }
  279.  
  280. }  //end loop
  281.  
  282. /*
  283.    * calc_adc_sequence(ADCx_Sequence) converts the SQR3 6 channels' (each ADC1 and ADC2) list into
  284.  * a valid 6 X 5=30 bits sequence format and returns that 30 bits number.
  285.  * For more channels, repeat the same for SQR2, SQR1. (For SQR1 4 channels only!)
  286.  */
  287. uint32  calc_adc_sequence(uint8 adc_sequence_array[6])
  288. {
  289.   adc_sequence=0;
  290.  
  291.   for (int i=0;i<6;i++)     // There are 6 available sequences in each SQR3 SQR2, and 4 in SQR1.
  292.   {
  293.     /*This function converts the array into one number by multiplying each 5-bits channel numbers
  294.      by multiplications of 2^5
  295.      */
  296.     adc_sequence=adc_sequence + adc_sequence_array[i]*pow(2,(i*5));  
  297.   }
  298.   return adc_sequence;
  299. }   //end calc_adc_sequence
  300.  
  301. void print_registers()
  302. {
  303.   SerialUSB.print("ADC1, CR1\t");
  304.   SerialUSB.println(ADC1->regs->CR1,BIN);
  305.   SerialUSB.print("ADC2, CR1\t");
  306.   SerialUSB.println(ADC2->regs->CR1,BIN);
  307.   SerialUSB.print("ADC1, CR2\t");
  308.   SerialUSB.println(ADC1->regs->CR2,BIN);
  309.   SerialUSB.print("ADC2, CR2\t");
  310.   SerialUSB.println(ADC2->regs->CR2,BIN);
  311.   SerialUSB.print("ADC1, SQR3\t");  
  312.   SerialUSB.println(ADC1->regs->SQR3,BIN);
  313.   SerialUSB.print("ADC2, SQR3\t");
  314.   SerialUSB.println(ADC2->regs->SQR3,BIN);
  315.   SerialUSB.print("ADC1, SQR1\t");  
  316.   SerialUSB.println(ADC1->regs->SQR1,BIN);
  317.   SerialUSB.print("ADC2, SQR1\t");
  318.   SerialUSB.println(ADC2->regs->SQR1,BIN);
  319.   SerialUSB.print("ADC1, SR\t");
  320.   SerialUSB.println(ADC1->regs->SR,BIN);
  321.   SerialUSB.print("DMA1, CCR1\t");
  322.   SerialUSB.println(DMA1->regs->CCR1,BIN);
  323.   SerialUSB.print("DMA1, ISR\t");
  324.   SerialUSB.println(DMA1->regs->ISR,BIN);
  325.   SerialUSB.print("DMA1, CPAR1\t");
  326.   SerialUSB.println(DMA1->regs->CPAR1,BIN);
  327.   SerialUSB.println();
  328.   SerialUSB.println();
  329. } //end print_registers
  330.  
  331. void welcome_message()
  332. {
  333.   SerialUSB.println("Welcome to the Maple dual simultaneous ADC demo / template by samtal");
  334.   SerialUSB.println();
  335.   SerialUSB.println("Real-time input parameters:");
  336.  SerialUSB.println("'r' to display the relevant registers, stop by 'R'.");
  337.  SerialUSB.println("'v' to display data in real volts, stop by 'V'.");
  338.  SerialUSB.println("'b' to display the adc raw data in bin to dec format. Stop by 'B'.");
  339.  SerialUSB.println("'t' to toggle on/off output pin 23 used as voltage input");
  340.  SerialUSB.println(" tied to input pin 27 (an. chan. 8) and pin 26 (dig in");
  341.  SerialUSB.println();
  342.  SerialUSB.println("Notes: This sample enables 6 X 2 Analog In channels in SQR3 only,");  
  343.  SerialUSB.println("out of which any even pair number can be used (the 'adc_length' in pairs");
  344.  SerialUSB.println();
  345. SerialUSB.println("Enter d to display this message");
  346.  SerialUSB.println();
  347. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement