Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVDParser._parse_peripheral() should handle clusters #47

Open
mbolivar opened this issue Dec 20, 2017 · 2 comments
Open

SVDParser._parse_peripheral() should handle clusters #47

mbolivar opened this issue Dec 20, 2017 · 2 comments

Comments

@mbolivar
Copy link

Peripherals defined in some SVDs (for example, the SAADC peripheral in https://github.com/posborne/cmsis-svd/blob/master/data/Nordic/nrf52.svd) declare some registers via clusters.

However, the current SVDParser._parse_peripheral() implementation in parser.py (i.e. https://github.com/posborne/cmsis-svd/blob/master/python/cmsis_svd/parser.py#L240) does not take this into account. This means that the parsed peripheral's register list is missing information that is provided in the SVD file.

Here is an example of clusters as used by the SAADC peripheral definition for nRF52:

<peripheral>
  <name>SAADC</name>
  <description>Analog to Digital Converter</description>
  <!-- [snip] -->
  <registers>
    <register>
      <name>TASKS_START</name>
      <!-- [snip] -->
    </register>
    <register>
      <name>TASKS_SAMPLE</name>
      <!-- [snip] -->
    </register>
    <!-- [snip] -->
    <cluster>
      <name>RESULT</name>
      <description>RESULT EasyDMA channel</description>
      <headerStructName>SAADC_RESULT</headerStructName>
      <addressOffset>0x62C</addressOffset>
      <register>
	<name>PTR</name>
	<description>Data pointer</description>
	<addressOffset>0x000</addressOffset>
	<access>read-write</access>
	<fields>
	  <field>
	    <name>PTR</name>
	    <description>Data pointer</description>
	    <lsb>0</lsb>
	    <msb>31</msb>
	  </field>
	</fields>
      </register>
      <register>
	<name>MAXCNT</name>
	<description>Maximum number of buffer words to transfer</description>
	<addressOffset>0x004</addressOffset>
	<access>read-write</access>
	<fields>
	  <field>
	    <name>MAXCNT</name>
	    <description>Maximum number of buffer words to transfer</description>
	    <lsb>0</lsb>
	    <msb>15</msb>
	  </field>
	</fields>
      </register>
      <register>
	<name>AMOUNT</name>
	<description>Number of buffer words transferred since last START</description>
	<addressOffset>0x008</addressOffset>
	<access>read-only</access>
	<fields>
	  <field>
	    <name>AMOUNT</name>
	    <description>Number of buffer words transferred since last START. This register can be read after an END or STOPPED event.</description>
	    <lsb>0</lsb>
	    <msb>15</msb>
	  </field>
	</fields>
      </register>
    </cluster>
  </registers>
</peripheral>

Note that the "clusters" node has a top-level address offset, and that the individual registers within a cluster have offsets relative to that top-level offset. Otherwise the register fields within a cluster are very similar to the register nodes already parsed (they contain name, description, addressOffset, access, and perhaps fields.

Can _parse_peripheral() be extended to support clusters as well?

@mbolivar
Copy link
Author

Looking at this SAADC peripheral a bit more, there are at least two cases to support:

  • Cluster does not contain dim, dimIncrement, and dimIndex child nodes (such as the cluster named RESULT described above). In that case, the cluster contains a simple list of registers, whose address offsets are relative to the cluster addressOffset.

  • Cluster does contain dim, dimIncrement, dimIndex child nodes, like the cluster named "CH[%s]". In this case, the registers in the cluster are the elements of an array of registers. Each register has an address offset from the peripheral base equal to (addressOffset of the cluster node) + dimIncrement * (dimIndex value) + (addressOffset of the register node).

@mbolivar
Copy link
Author

Here's a snippet of the vendor-provided CMSIS core header showing how the two cases break down in memory:

typedef struct {
  __IO uint32_t  LIMITH;                            /*!< Description cluster[0]: Last results is equal or above CH[0].LIMIT.HIGH */
  __IO uint32_t  LIMITL;                            /*!< Description cluster[0]: Last results is equal or below CH[0].LIMIT.LOW */
} SAADC_EVENTS_CH_Type;

typedef struct {
  __IO uint32_t  PSELP;                             /*!< Description cluster[0]: Input positive pin selection for CH[0]        */
  __IO uint32_t  PSELN;                             /*!< Description cluster[0]: Input negative pin selection for CH[0]        */
  __IO uint32_t  CONFIG;                            /*!< Description cluster[0]: Input configuration for CH[0]                 */
  __IO uint32_t  LIMIT;                             /*!< Description cluster[0]: High/low limits for event monitoring
                                                         a channel                                                             */
} SAADC_CH_Type;

typedef struct {
  __IO uint32_t  PTR;                               /*!< Data pointer                                                          */
  __IO uint32_t  MAXCNT;                            /*!< Maximum number of buffer words to transfer                            */
  __I  uint32_t  AMOUNT;                            /*!< Number of buffer words transferred since last START                   */
} SAADC_RESULT_Type;

typedef struct {                                    /*!< SAADC Structure                                                       */
  __O  uint32_t  TASKS_START;                       /*!< Start the ADC and prepare the result buffer in RAM                    */
  __O  uint32_t  TASKS_SAMPLE;                      /*!< Take one ADC sample, if scan is enabled all channels are sampled      */
  __O  uint32_t  TASKS_STOP;                        /*!< Stop the ADC and terminate any on-going conversion                    */
  __O  uint32_t  TASKS_CALIBRATEOFFSET;             /*!< Starts offset auto-calibration                                        */
  __I  uint32_t  RESERVED0[60];
  __IO uint32_t  EVENTS_STARTED;                    /*!< The ADC has started                                                   */
  __IO uint32_t  EVENTS_END;                        /*!< The ADC has filled up the Result buffer                               */
  __IO uint32_t  EVENTS_DONE;                       /*!< A conversion task has been completed. Depending on the mode,
                                                         multiple conversions might be needed for a result to be transferred
                                                          to RAM.                                                              */
  __IO uint32_t  EVENTS_RESULTDONE;                 /*!< A result is ready to get transferred to RAM.                          */
  __IO uint32_t  EVENTS_CALIBRATEDONE;              /*!< Calibration is complete                                               */
  __IO uint32_t  EVENTS_STOPPED;                    /*!< The ADC has stopped                                                   */
  SAADC_EVENTS_CH_Type EVENTS_CH[8];                /*!< Unspecified                                                           */
  __I  uint32_t  RESERVED1[106];
  __IO uint32_t  INTEN;                             /*!< Enable or disable interrupt                                           */
  __IO uint32_t  INTENSET;                          /*!< Enable interrupt                                                      */
  __IO uint32_t  INTENCLR;                          /*!< Disable interrupt                                                     */
  __I  uint32_t  RESERVED2[61];
  __I  uint32_t  STATUS;                            /*!< Status                                                                */
  __I  uint32_t  RESERVED3[63];
  __IO uint32_t  ENABLE;                            /*!< Enable or disable ADC                                                 */
  __I  uint32_t  RESERVED4[3];
  SAADC_CH_Type CH[8];                              /*!< Unspecified                                                           */
  __I  uint32_t  RESERVED5[24];
  __IO uint32_t  RESOLUTION;                        /*!< Resolution configuration                                              */
  __IO uint32_t  OVERSAMPLE;                        /*!< Oversampling configuration. OVERSAMPLE should not be combined
                                                         with SCAN. The RESOLUTION is applied before averaging, thus
                                                          for high OVERSAMPLE a higher RESOLUTION should be used.              */
  __IO uint32_t  SAMPLERATE;                        /*!< Controls normal or continuous sample rate                             */
  __I  uint32_t  RESERVED6[12];
  SAADC_RESULT_Type RESULT;                         /*!< RESULT EasyDMA channel                                                */
} NRF_SAADC_Type;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant