Repository: google/cyanobyte (language: python)

Issue:
Improve Markdown template
Auto-generated markdown files get hosted in [the developer docs](https://cyanobyte.dev/docs/reference/peripheral-docs/)

* [ ] Add more details on the technical specs of device & registers (See LaTeX and HTML templates)
* [ ] Improve register descriptions, add register addresses to distinguish them more. Use key & title or maybe just key.
* [ ] Add fields
* [ ] MCP9808 improve description

The LSM303D and TCS3472 have good descriptions. The others could use some improvement.


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index 2c9ee90..f8a606e 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,12 @@
-# Peripheral Codegen
+# Cyanobyte - Machine readable datasheets for documentation & codegen
+
+![logo](https://github.com/google/cyanobyte/raw/master/cyanobyte_logo.png)
+
 This project is an example of how to describe peripherals with an intermediary layer (YAML files) which can be used to generate library files for a peripheral.
 
 It can also generate reference documentation for a peripheral, useful for embedding into datasheets.
 
-The tool works well for I2C devices, while SPI support is in alpha.
+The tool works well for I2C devices, while SPI support is in progress.
 
 This is not an official Google product.
 
diff --git a/cyanobyte_logo.png b/cyanobyte_logo.png
new file mode 100644
index 0000000..477c4a3
Binary files /dev/null and b/cyanobyte_logo.png differ
diff --git a/cyanobyte_logo_x32.png b/cyanobyte_logo_x32.png
new file mode 100644
index 0000000..e915ecc
Binary files /dev/null and b/cyanobyte_logo_x32.png differ
diff --git a/docs/content/_index.html b/docs/content/_index.html
index beb8602..0b8db27 100644
--- a/docs/content/_index.html
+++ b/docs/content/_index.html
@@ -5,6 +5,7 @@
 +++
 
 {{< blocks/cover title="Cyanobyte: An intermediate representation for hardware peripheral I/O" image_anchor="top" height="full" color="orange" >}}
+<img src="https://github.com/google/cyanobyte/raw/master/cyanobyte_logo.png" alt="Cyanobyte logo" />
 <div class="mx-auto">
 	<a class="btn btn-lg btn-primary mr-3 mb-4" href="{{< relref "/docs" >}}">
 		Learn More <i class="fas fa-arrow-alt-circle-right ml-2"></i>
@@ -12,7 +13,7 @@
 	<a class="btn btn-lg btn-secondary mr-3 mb-4" href="https://github.com/google/cyanobyte">
 		View Source <i class="fab fa-github ml-2 "></i>
 	</a>
-	<p class="lead mt-5">Automatically generate drivers without writing code!</p>
+	<p class="lead mt-5">Automatically generate peripheral drivers without writing code!</p>
 	<div class="mx-auto mt-5">
 		{{< blocks/link-down color="info" >}}
 	</div>
@@ -24,7 +25,7 @@
 {{% blocks/feature icon="fa-list" title="Cyanobyte goals:" %}}
 <ul style="text-align: left">
 	<li>Open source</li>
-	<li>Standarized</li>
+	<li>Standarized core specification</li>
 	<li>Support any embedded platforms</li>
 	<li>Easily extensible</li>
 </ul>
diff --git a/docs/content/blog/news/2019-09/live.md b/docs/content/blog/news/2019-09/live.md
index 0c407db..b39101c 100644
--- a/docs/content/blog/news/2019-09/live.md
+++ b/docs/content/blog/news/2019-09/live.md
@@ -1,6 +1,6 @@
 ---
 date: 2019-09-06
-title: "cyanobyte-dev"
+title: "Cyanobyte.dev published"
 linkTitle: "Cyanobyte.dev published"
 description: "The Cyanobyte website provides resources and documentation"
 author: Nick Felker
diff --git a/docs/content/blog/news/2020-04/datasheet.md b/docs/content/blog/news/2020-04/datasheet.md
index 959c498..5dc39ed 100644
--- a/docs/content/blog/news/2020-04/datasheet.md
+++ b/docs/content/blog/news/2020-04/datasheet.md
@@ -1,6 +1,6 @@
 ---
 date: 2020-04-12
-title: "using-machine-readable-datasheets"
+title: "Using machine-readable datasheets to create datasheets with Cyanobyte and LaTeX"
 linkTitle: "Using machine-readable datasheets to create datasheets with Cyanobyte and LaTeX"
 description: "Datasheets are useful reference documents that engineers are already familiar with. Could it be possible to generate PDFs just as easily as generating code?"
 author: Nick Felker
@@ -15,7 +15,7 @@ Letting subject matter experts focus on either the peripheral specification or t
 This approach is not just useful for code generation. It also can be used to generate [Markdown pages](https://cyanobyte.dev/docs/reference/peripheral-docs/com/cyanobyte/bmp280/) that are hosted in the developer documentation as part of the continuous delivery service.
 
 <img src="https://miro.medium.com/max/700/1*NwWVOyKB5-YxH0DGWz6y_Q.png" /><br>
-<small>https://cyanobyte.dev/docs/reference/peripheral-docs/com/cyanobyte/bmp280/ is autogenerated and hosted</a>
+<small>https://cyanobyte.dev/docs/reference/peripheral-docs/com/cyanobyte/bmp280/ is autogenerated and hosted</small>
 
 The success of this started getting me thinking about datasheets in general. They are useful reference documents that engineers are already familiar with. Could it be possible to generate PDFs just as easily as generating code?
 
@@ -29,17 +29,17 @@ Adapting the template was not too difficult. I replaced some of the graphics wit
 Once I finished it, I was able to use Overleaf to render the results, and I was pretty happy with how it turned out.
 
 <img src="https://miro.medium.com/max/627/1*HjETag6uTwBnZkyFk5XfXA.png" /><br>
-<small>PDF render of [ADS1015](https://raw.githubusercontent.com/google/cyanobyte/a5701ce6048f69b1e3bb02a916e9991eee6e45eb/test/sampleData/datasheet/ADS1015.tex)</a>
+<small>PDF render of [ADS1015](https://raw.githubusercontent.com/google/cyanobyte/a5701ce6048f69b1e3bb02a916e9991eee6e45eb/test/sampleData/datasheet/ADS1015.tex)</small>
 
 The template starts with an Overview with interesting information, register descriptions, then tables. The first table is an overview of all the registers. The next section then goes into more detail about each register if it is made up of smaller fields.
 
 <img src="https://miro.medium.com/max/629/1*Dhw1Gxj6ltzzm3K4oieqWQ.png" /><br>
-<small>PDF render of [BMP280](https://raw.githubusercontent.com/google/cyanobyte/a5701ce6048f69b1e3bb02a916e9991eee6e45eb/test/sampleData/datasheet/BMP280.tex)</small>
+<small>PDF render of [BMP280](https://raw.githubusercontent.com/google/cyanobyte/a5701ce6048f69b1e3bb02a916e9991eee6e45eb/test/sampleData/datasheet/BMP280.tex).</small>
 
 Functions are also displayed in tables, showing the name of the function and the return type.
 
 <img src="https://miro.medium.com/max/617/1*-ZQ1i8IjPPiYyZOS44o-lA.png" /><br>
-<small>PDF render of [LSM303D](https://raw.githubusercontent.com/google/cyanobyte/a5701ce6048f69b1e3bb02a916e9991eee6e45eb/test/sampleData/datasheet/LSM303D.tex)</a>.
+<small>PDF render of [LSM303D](https://raw.githubusercontent.com/google/cyanobyte/a5701ce6048f69b1e3bb02a916e9991eee6e45eb/test/sampleData/datasheet/LSM303D.tex).</small>
 
 Functions with multiple returns, in a tuple or array, are displayed as a comma-separated list.
 
diff --git a/docs/content/blog/news/2021-02/webpage.md b/docs/content/blog/news/2021-02/webpage.md
index b67f4cb..23c5223 100644
--- a/docs/content/blog/news/2021-02/webpage.md
+++ b/docs/content/blog/news/2021-02/webpage.md
@@ -1,6 +1,6 @@
 ---
 date: 2021-02-16
-title: "web-documentation"
+title: "Cyanobyte turns machine-readable datasheets into web documentation"
 linkTitle: "Cyanobyte turns machine-readable datasheets into web documentation"
 description: "One benefit of Cyanobyte is around documentation. By defining it in this way, not only can code be generated, but any type of file. In the past, LaTeX was used as the basis for generating documentation as PDFs. Now, there is a new type of output: HTML."
 author: Nick Felker
diff --git a/docs/content/blog/news/2021-03/callbacks.md b/docs/content/blog/news/2021-03/callbacks.md
new file mode 100644
index 0000000..193be24
--- /dev/null
+++ b/docs/content/blog/news/2021-03/callbacks.md
@@ -0,0 +1,93 @@
+---
+date: 2021-03-30
+title: "Implementing delays in Cyanobyte through a callback mechanism"
+linkTitle: "Implementing delays in Cyanobyte through a callback mechanism"
+description: "For the BMP180 temperature/pressure sensor, a small delay needs to added after getting the temperature before the pressure can be calculated accurately."
+author: Nick Felker
+---
+
+<small>This article was cross-posted [from Medium](https://medium.com/@fleker/15d16c7901ec)</small>
+
+<img src="https://cdn-images-1.medium.com/max/1400/1*B6We_hYPlRQLMlsRjIgDtQ.png" alt="Cyanobyte Logo" />
+<br>
+<small>Cyanobyte Logo</small>
+
+Over the past few years I've continued to iterate on this idea I've had for a while. When building applications for embedded devices, you've often need to connect to a peripheral using something like I2C. This requires you to either look for an existing library for that device on your platform, or write the library yourself from scratch.
+
+For embedded software this is often an exercise in frustration, having to read through convoluted datasheets or cherry-picking from manufacturer sample code.
+
+[Cyanobyte](https://github.com/google/cyanobyte/) was created to define a common spec for peripherals in a machine-readable format which could then be converted into platform-specific code through a code generator. Since the start, I've defined a number of peripherals in the format and support a number of platforms including Raspberry Pi, Arduino, Espruino (JavaScript), a generic C platform, and several documentation templates.
+
+<img src="https://cdn-images-1.medium.com/max/1400/1*DkJMoiFOTuMvzIK-rA5qHw.png" />
+<br>
+<small>Directory listing of all template files</small>
+
+Normally this is not the best way to create a product. You are supposed to start with one instance and polish that before moving onto the next thing. However, in my case I intentionally added support for a number of disparate platforms.
+
+Embedded platforms are all different, and in order to verify the Cyanobyte spec would actually work for developers I had to try out a number of different platforms.
+
+When I started out, I used the Raspberry Pi and Python. When moving to Arduino, suddenly everything had to be properly typed. Ensuring that type-safety was in the spec was critical to creating something that would gain wider adoption.
+
+<hr>
+
+In particular this brings me around to delays, another implementation detail that actually has significant platform differences. For the BMP180 temperature/pressure sensor, a small delay needs to added after getting the temperature before the pressure can be calculated accurately.
+
+On the Raspberry Pi and Arduino, for example, they have blocking delay functions. It would be all too easy for me to add a simple delay step in the larger list of logical operations:
+
+<script src="https://gist.github.com/Fleker/0b27611aaa40c8dfce51d941d6026910.js"></script>
+
+This would result in blocking Arduino code:
+
+<script src="https://gist.github.com/Fleker/1a9cbd08317453b5e8decca1e8e10730.js"></script>
+
+And everything would've been fine.
+
+However, because there are a number of additional platforms I am unable to make this assumption and spec definition. Not every platform supports blocking delays nor do they want to.
+
+Some embedded platforms will use a task scheduler so that they can move on to another computation while they wait. Some platforms support multiple threads or cores and will need to use asynchronous logic instead.
+
+With the concept of callbacks in mind, I had to update the spec. This would place subsequent logic into a subarray and label the delay to use in callback names:
+
+<script src="https://gist.github.com/Fleker/d10edaff74f58971ee66ac85764ec1c1.js"></script>
+
+This change has no bearing on Arduino, as it keeps its blocking delay. However, now we can use this to define callbacks for the [Espruino platform](https://www.espruino.com/) with JavaScript, which uses [the `setTimeout` function](https://www.espruino.com/Arduino+Differences) for delays.
+
+So my logic now needs to accept a callback method as a function parameter and then execute it rather than returning a value directly:
+
+<script src="https://gist.github.com/Fleker/8094eb6f1607f0805b5efbf6190865f2.js"></script>
+
+This output would have been lot more difficult to generate had the delay remained blocking, and would've made certain types of actions like multi-threading essentially infeasible. This additional flexibility will be useful for advanced use-cases without having to refactor this in the future.
+
+<hr>
+
+There is another template that gave me additional trouble, which was the generic embedded C files. Rather than mandating a certain platform or library for I2C writes and reads, this uses function pointers for read/write operations. It makes the function headers a bit more complex, but gives you flexibility that doesn't exist in a strict Arduino template.
+
+<script src="https://gist.github.com/Fleker/62f4fdeb077bc5601761435ea7f7831f.js"></script>
+
+This flexibility means that delays cannot be assumed to be available. Perhaps you would have your own task scheduler. So it seemed like the best approach was to return the `after` field as a function pointer and you would be responsible for the delay:
+
+<script src="https://gist.github.com/Fleker/6896ea7e59c535cee6804db4578eb721.js"></script>
+
+I committed this code and thought for a minute. The pointers in pointers is still convoluted, but seemed reasonable enough. However, I discovered an even larger flaw in the behavior of this code.
+
+You see, my `_callback_celsius` function needs to calculate `rawComp` based on the `temperature` variable. However, now that we are in a separate function all of our previous scoped variables are not accessible. `temperature` no longer exists and we cannot go back and get it.
+
+What could I do? Well, what if I required you to re-enter all of the variables in the correct order? A bit onerous:
+
+<script src="https://gist.github.com/Fleker/41507a7ee895b77bec487c9a9540fc79.js"></script>
+
+But there also is still no way for you to know the value of `temperature`. It is an internal value to this auto-generated function.
+
+I ended up deciding the best way was to define a struct that represented the function's state and then return that instead of a callback directly:
+
+<script src="https://gist.github.com/Fleker/02440fc6c9e0e31c099b87adbe5ea181.js"></script>
+
+<script src="https://gist.github.com/Fleker/5d5ef6395a18e9f17dfddf2512212493.js"></script>
+
+Finally I had managed to get every platform to meet expectations and I merged [the pull request](https://github.com/google/cyanobyte/pull/258/files). It took some time, and the implementation may still not be perfect, but it will be satisfactory for the BMP180.
+
+What is the moral of this blog post? Callbacks are hard. Blocking code will always be easier to write, but may end up preventing you from advanced use-cases.
+
+For Cyanobyte, the effort to try doing too much has had trade-offs. Now that the project has continued to evolve, some of those seams have become more obvious. But it also has allowed me to better design a spec that will work for the most developers. It will save me time going forward and developer frustration as they need to perform refactors.
+
+You can visit the project on GitHub at https://github.com/google/cyanobyte/ which has instructions on how to download the toolchain and get started building your own peripheral drivers.
diff --git a/docs/content/docs/Reference/unanswered.md b/docs/content/docs/Reference/unanswered.md
index ac4b3b6..6c01753 100644
--- a/docs/content/docs/Reference/unanswered.md
+++ b/docs/content/docs/Reference/unanswered.md
@@ -3,5 +3,7 @@ title: "Unanswered questions"
 linkTitle: "Unanswered questions"
 weight: 4
 description: >
-  Some peripherals have default values they are set to on reset. Should we include that information in the specification?
----
\ No newline at end of file
+  Open areas of discussion
+---
+
+* Some peripherals have default values they are set to on reset. Should we include that information in the specification? How?
diff --git a/peripherals/ADS1015.yaml b/peripherals/ADS1015.yaml
index f834d18..1614806 100644
--- a/peripherals/ADS1015.yaml
+++ b/peripherals/ADS1015.yaml
@@ -37,18 +37,18 @@ registers:
     address: 0x01
     length: 16
     title: ADC config
-    description: Describes the specifics of the sensing implementation
+    description: Defines sensing implementation and options.
   Conversion:
     address: 0x00
     length: 16
     title: ADC Value
-    description: Conversion register contains the result of the last conversion
+    description: Contains the result of the last conversion.
     readWrite: R
 fields:
   SampleRate:
-    title: Setup sample rate for reading analog voltage
+    title: Sample rate
     description: |
-      This sets the samples-per-second value
+      Sets the sample read in samples-per-second for reading analog voltage.
     register: '#/registers/Config'
     readWrite: 'W'
     bitStart: 7
@@ -77,9 +77,9 @@ fields:
         title: 3300 samples/second
         value: 0b110
   ProgrammableGain:
-    title: Setup programmable gain
+    title: Programmable gain
     description: |
-      This sets the programmable gain for reading analog voltage
+      Sets the programmable gain for reading analog voltage in voltage.
     register: '#/registers/Config'
     readWrite: 'W'
     bitStart: 11
@@ -105,9 +105,9 @@ fields:
         title: Plus/minus 0.256V
         value: 0b101
   DeviceOperatingMode:
-    title: Set the operating mode
+    title: Operating mode
     description: |
-      This bit controls the operating mode
+      Controls the operating mode for reading analog voltage.
     register: '#/registers/Config'
     readWrite: 'W'
     bitStart: 8
@@ -121,9 +121,9 @@ fields:
           title: Single-shot or power-down state
           value: 1
   Channel:
-    title: Set the channel to read
+    title: Channel to read
     description: |
-      This sets the channel for reading analog voltage
+      Sets the channel for reading analog voltage.
     register: '#/registers/Config'
     readWrite: 'n'
     bitStart: 14
@@ -144,8 +144,8 @@ fields:
         value: 0b11
 functions:
   analog:
-    title: Value read from ADC
-    description: Reads the analog voltage in Volts
+    title: Read analog voltage
+    description: Reads the analog voltage in Volts.
     computed:
       read:
         input:
diff --git a/peripherals/BH1750FVI.yaml b/peripherals/BH1750FVI.yaml
index 5a62542..d95fb6b 100644
--- a/peripherals/BH1750FVI.yaml
+++ b/peripherals/BH1750FVI.yaml
@@ -41,13 +41,13 @@ registers:
     address: 0x00
     length: 0
     title: Power Down
-    description: No active state
+    description: State when the device is not active.
     readWrite: W
   PowerOn:
     address: 0x01
     length: 0
     title: Power On
-    description: Waiting for measurement command
+    description: State when device is on and waiting measurement command.
     readWrite: W
   Reset:
     address: 0x07
@@ -58,25 +58,25 @@ registers:
   ContinuousHResMode:
     address: 0b00010000
     length: 0
-    title: Continuously H-Resolution Mode
+    title: Continuously High-Resolution Mode
     description: Start measurement at 1lx resolution. Typically 120ms.
     readWrite: W
   ContinuousHRes2Mode:
     address: 0b00010001
     length: 0
-    title: Continously H-Resolution Mode2
+    title: Continously High-Resolution Mode 2
     description: Start measurement at 0.5lx resolution. Typically 120ms.
     readWrite: W
   ContinuouslyLResMode:
     address: 0b00010011
     length: 0
-    title: Continuously L-Resolution Mode
+    title: Continuously Low-Resolution Mode
     description: Start measurement at 4lx resolution. Typically 16ms.
     readWrite: W
   OnceHResMode:
     address: 0b00100000
     length: 0
-    title: One Time H-Resolution Mode
+    title: One Time High-Resolution Mode
     description: |
       Start measurement at 1lx resolution. Typically 120ms.
       Power Down after measurement.
@@ -84,7 +84,7 @@ registers:
   OnceHRes2Mode:
     address: 0b0010_0001
     length: 0
-    title: One Time H-Resolution Mode2
+    title: One Time High-Resolution Mode2
     description: |
       Start measurement at 0.5lx resolution. Typically 120ms.
       Power Down after measurement.
@@ -92,7 +92,7 @@ registers:
   OnceLResMode:
     address: 0b0010_0011
     length: 0
-    title: One Time L-Resolution Mode
+    title: One Time Low-Resolution Mode
     description: |
       Start measurement at 4lx resolution. Typically 16ms.
       Power Down after measurement.
@@ -101,7 +101,7 @@ registers:
 functions:
   _lifecycle:
     title: Powers on the device
-    description: Sends a POWER ON cmd to device
+    description: Sends a POWER ON cmd to device.
     computed:
       Begin:
         logic:
@@ -109,7 +109,7 @@ functions:
               register: '#/registers/PowerOn'
   command:
     title: Commands to device
-    description: Things you can do to device
+    description: Commands that can be sent to the device.
     computed:
       PowerDown:
         logic:
@@ -125,7 +125,7 @@ functions:
               register: '#/registers/Reset'
   read:
     title: Read light intensity from device
-    description: Read light intensity from device
+    description: Read light intensity from device.
     computed:
       LightIntensity:
         variables:
diff --git a/peripherals/BMP180.yaml b/peripherals/BMP180.yaml
index 7f1b08a..d5928e8 100644
--- a/peripherals/BMP180.yaml
+++ b/peripherals/BMP180.yaml
@@ -37,83 +37,83 @@ registers:
   Control:
     address: 0xF4
     length: 8
-    title: Register to write commands
-    description: Register stores what the measurement type should be
+    title: Command register.
+    description: Stores the current measurement type.
     readWrite: 'W'
   Result:
     address: 0xF6
     length: 16
-    title: Register that stores measurement results
-    description: Register stores most recent measurement result
+    title: Measurement results
+    description: Stores the most recent measurement result.
     readWrite: 'R'
   TempCal3:
     address: 0xAE
     length: 16
     title: Temperature calibration 3
-    description: For calibration
+    description: Third constant register for temperature measurement calibration.
     readWrite: 'R'
   TempCal4:
     address: 0xB0
     length: 16
     title: Temperature calibration 4
     signed: false
-    description: For calibration
+    description: Fourth constant register for temperature measurement calibration.
     readWrite: 'R'
   TempCal5:
     address: 0xB2
     length: 16
     title: Temperature calibration 5
     signed: false
-    description: For calibration
+    description: Fifth constant register for temperature measurement calibration.
     readWrite: 'R'
   TempCal6:
     address: 0xB4
     length: 16
     title: Temperature calibration 6
     signed: false
-    description: For calibration
+    description: Sixth constant register for temperature measurement calibration.
     readWrite: 'R'
   TempCalMC:
     address: 0xBC
     length: 16
     title: Temperature calibration MC
-    description: For calibration
+    description: Constant register for temperature measurement calibration.
     readWrite: 'R'
   TempCalMD:
     address: 0xBE
     length: 16
     title: Temperature calibration MD
-    description: For calibration
+    description: Constant register for temperature measurement calibration.
     readWrite: 'R'
   PressureCalAC1:
     address: 0xAA
     length: 16
     title: Pressure calibration AC1
-    description: For calibration
+    description: Constant register for pressure measurement calibration.
     readWrite: 'R'
   PressureCalAC2:
     address: 0xAC
     length: 16
     title: Pressure calibration AC2
-    description: For calibration
+    description: Constant register for pressure measurement calibration.
     readWrite: 'R'
   PressureCalVB1:
     address: 0xB6
     length: 16
     title: Pressure calibration VB1
-    description: For calibration
+    description: Constant register for pressure measurement calibration.
     readWrite: 'R'
   PressureCalVB2:
     address: 0xB8
     length: 16
     title: Pressure calibration VB2
-    description: For calibration
+    description: Constant register for pressure measurement calibration.
     readWrite: 'R'
 
 functions:
   temperature:
     title: Temperature as read by sensor
-    description: Reads the temperature
+    description: Reads the temperature as a raw value or in Celsius.
     register: '#/registers/Control'
     computed:
       asCelsius:
diff --git a/peripherals/BMP280.yaml b/peripherals/BMP280.yaml
index dc10ec4..abd15d8 100644
--- a/peripherals/BMP280.yaml
+++ b/peripherals/BMP280.yaml
@@ -40,126 +40,126 @@ registers:
     address: 0xFA
     length: 8
     title: Temperature MSB
-    description: Part 1 of temperature
+    description: Most-significant bit of temperature measurement result.
     readWrite: R
   TempLsb:
     address: 0xFB
     length: 8
     title: Temperature LSB
-    description: Part 2 of temperature
+    description: Middle-significant bit of temperature measurement result.
     readWrite: R
   TempXlsb:
     address: 0xFC
     length: 8
     title: Temperature XLSB
-    description: Final part of temperature
+    description: Least-significant bit of temperature measurement result.
     readWrite: R
   DigT1:
     address: 0x88
     length: 16
     title: Digital Temperature Compensation 1
-    description: Used for Celcius conversion
+    description: Compensation register used for temperature measurement result.
     readWrite: R
     signed: false
   DigT2:
     address: 0x8A
     length: 16
     title: Digital Temperature Compensation 2
-    description: Used for Celcius conversion
+    description: Compensation register used for temperature measurement result.
     readWrite: R
     signed: true
   DigT3:
     address: 0x8C
     length: 16
     title: Digital Temperature Compensation 3
-    description: Used for Celcius conversion
+    description: Compensation register used for temperature measurement result.
     readWrite: R
     signed: true
   PressureMsb:
     address: 0xF7
     length: 8
     title: Pressure MSB
-    description: Part 1 of Pressure
+    description: Most-significant bit of pressure measurement result.
     readWrite: R
   PressureLsb:
     address: 0xF8
     length: 8
     title: Pressure LSB
-    description: Part 2 of Pressure
+    description: Middle-significant bit of pressure measurement result.
     readWrite: R
   PressureXlsb:
     address: 0xF9
     length: 8
     title: Pressure XLSB
-    description: Part 3 of Pressure
+    description: Least-significant bit of pressure measurement result.
     readWrite: R
   DigP1:
     address: 0x8E
     length: 16
     signed: false
     title: Digital Pressure Compensation 1
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP2:
     address: 0x90
     length: 16
     signed: true
     title: Digital Pressure Compensation 2
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP3:
     address: 0x92
     length: 16
     signed: true
     title: Digital Pressure Compensation 3
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP4:
     address: 0x94
     length: 16
     signed: true
     title: Digital Pressure Compensation 4
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP5:
     address: 0x96
     length: 16
     signed: true
     title: Digital Pressure Compensation 5
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP6:
     address: 0x98
     length: 16
     signed: true
     title: Digital Pressure Compensation 6
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP7:
     address: 0x9A
     length: 16
     signed: true
     title: Digital Pressure Compensation 7
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP8:
     address: 0x9C
     length: 16
     signed: true
     title: Digital Pressure Compensation 8
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
   DigP9:
     address: 0x9E
     length: 16
     signed: true
     title: Digital Pressure Compensation 9
-    description: Used for Pascals conversion
+    description: Compensation register used for Pascals conversion.
     readWrite: R
 functions:
   temperature:
     title: Temperature as read by sensor
-    description: Reads the temperature
+    description: Reads the temperature as a raw value or in Celsius.
     computed:
       asRaw:
         variables:
@@ -246,7 +246,7 @@ functions:
         return: celsius
   pressure:
     title: Pressure as read by sensor
-    description: Reads the atmospheric pressure
+    description: Reads the atmospheric pressure as a raw value or in hPa.
     computed:
       asRaw:
         variables:
diff --git a/peripherals/LSM303D.yaml b/peripherals/LSM303D.yaml
index a2807b6..fafb11d 100644
--- a/peripherals/LSM303D.yaml
+++ b/peripherals/LSM303D.yaml
@@ -38,80 +38,80 @@ registers:
   AccelerometerX_Low:
     address: 0xA8
     length: 8
-    title: Accelerometer X
-    description: Raw accelerometer data on X plane
+    title: Accelerometer X-Axis LSB
+    description: Least-significant bits for raw accelerometer data on X plane.
     readWrite: R
   AccelerometerX_High:
     address: 0xA9
     length: 8
-    title: Accelerometer X
-    description: Raw accelerometer data on X plane
+    title: Accelerometer X-Axis MSB
+    description: Most-significant bits for raw accelerometer data on X plane.
     readWrite: R
   AccelerometerY_Low:
     address: 0xAA
     length: 8
-    title: Accelerometer Y
-    description: Raw accelerometer data on Y plane
+    title: Accelerometer Y-Axis LSB
+    description: Least-significant bits for raw accelerometer data on Y plane.
     readWrite: R
   AccelerometerY_High:
     address: 0xAB
     length: 8
-    title: Accelerometer Y
-    description: Raw accelerometer data on Y plane
+    title: Accelerometer Y-Axis MSB
+    description: Most-significant bits for raw accelerometer data on Y plane.
     readWrite: R
   AccelerometerZ_Low:
     address: 0xAC
     length: 8
-    title: Accelerometer Z
-    description: Raw accelerometer data on Z plane
+    title: Accelerometer Z-Axis LSB
+    description: Least-significant bits for raw accelerometer data on Z plane.
     readWrite: R
   AccelerometerZ_High:
     address: 0xAD
     length: 8
-    title: Accelerometer Z
-    description: Raw accelerometer data on Z plane
+    title: Accelerometer Z-Axis MSB
+    description: Most-significant bits for raw accelerometer data on Z plane.
     readWrite: R
   MagnetometerX_Low:
     address: 0x88
     length: 8
-    title: Magnetometer X
-    description: Raw magnetometer data on X plane
+    title: Magnetometer X-Axis LSB
+    description: Least-significant bits for raw magnetometer data on X plane.
     readWrite: R
   MagnetometerX_High:
     address: 0x89
     length: 8
-    title: Magnetometer X
-    description: Raw magnetometer data on X plane
+    title: Magnetometer X-Axis MSB
+    description: Most-significant bits for raw magnetometer data on X plane.
     readWrite: R
   MagnetometerY_Low:
     address: 0x8A
     length: 8
-    title: Magnetometer Y
-    description: Raw magnetometer data on Y plane
+    title: Magnetometer Y-Axis LSB
+    description: Least-significant bits for raw magnetometer data on Y plane.
     readWrite: R
   MagnetometerY_High:
     address: 0x8B
     length: 8
-    title: Magnetometer Y
-    description: Raw magnetometer data on Y plane
+    title: Magnetometer Y-Axis MSB
+    description: Most-significant bits for raw magnetometer data on Y plane.
     readWrite: R
   MagnetometerZ_Low:
     address: 0x8C
     length: 8
-    title: Magnetometer Z
-    description: Raw magnetometer data on Z plane
+    title: Magnetometer Z-Axis LSB
+    description: Least-significant bits for raw magnetometer data on Z plane.
     readWrite: R
   MagnetometerZ_High:
     address: 0x8D
     length: 8
-    title: Magnetometer Z
-    description: Raw magnetometer data on Z plane
+    title: Magnetometer Z-Axis MSB
+    description: Most-significant bits for raw magnetometer data on Z plane.
     readWrite: R
 
 functions:
   acceleration:
     title: Acceleration as read by sensor
-    description: Measures the current acceleration
+    description: Measures the current acceleration for each plane.
     readWrite: 'n'
     computed:
       xPlane:
@@ -203,7 +203,7 @@ functions:
           - valueZ
   orientation:
     title: Orientation data as read by sensor
-    description: Reads the magnetic orientation
+    description: Reads the magnetic orientation for each plane and compass heading.
     readWrite: 'n'
     computed:
       xPlane:
diff --git a/peripherals/MCP4725.yaml b/peripherals/MCP4725.yaml
index e4075ae..59940e9 100644
--- a/peripherals/MCP4725.yaml
+++ b/peripherals/MCP4725.yaml
@@ -14,12 +14,12 @@
 cyanobyte: 0.1.0
 info:
   contact:
-    name: Nick Felker, Chris Frederickson
+    name: Nick Felker
     url: https://github.com/google/cyanobyte
     email: felker@google.com
   package: com.cyanobyte
   title: MCP4725
-  description: Microchip 4725 Digital-to-Analog Converter
+  description: Microchip Digital-to-Analog Converter
   copyright:
     name: Google Inc.
     date: '2019'
@@ -39,7 +39,8 @@ registers:
     length: 12
     title: Output voltage
     description: |
-      VOut = (Vcc * value) / 4096
+      Sets the output voltage relative to Vcc.
+      VOut = (Vcc * value) / 4096.
       The output is a range between 0 and Vcc with
       steps of Vcc/4096.
       In a 3.3v system, each step is 800 microvolts.
@@ -55,7 +56,7 @@ fields:
   digitalOut:
     title: Digital (binary) output
     description: |
-      Only allows you to send fully on or off
+      Set output as either fully on or fully off.
     register: '#/registers/EEPROM'
     readWrite: 'R/W'
     bitStart: 12
@@ -71,7 +72,7 @@ fields:
 functions:
   setVOut:
     title: Set output voltage
-    description: set vout
+    description: Set VOut as a function of Vcc.
     type: number
     register: '#/registers/EEPROM'
     bitStart: 12
@@ -85,8 +86,8 @@ functions:
           - output: = output / vcc * 4096
           - send: output
   getVOut:
-    title: Get output voltage
-    description: get vout
+    title: Read output voltage
+    description: Read VOut from EEPROM as a function of Vcc.
     type: number
     register: '#/registers/EEPROM'
     bitStart: 12
diff --git a/peripherals/MCP9808.yaml b/peripherals/MCP9808.yaml
index 515d254..66fad5c 100644
--- a/peripherals/MCP9808.yaml
+++ b/peripherals/MCP9808.yaml
@@ -1,12 +1,12 @@
 cyanobyte: 0.1.0
 info:
     title: MCP9808
-    description: This is a test description
+    description: Microchip Temperature Sensor
     package: com.cyanobyte
     contact:
-        name: 'Joe Smith'
-        url: 'http://example.com'
-        email: 'joe@example.com'
+        name: Nick Felker
+        url: https://github.com/google/cyanobyte
+        email: felker@google.com
     copyright:
         name: Google Inc.
         date: '2019'
diff --git a/peripherals/TCS3472.yaml b/peripherals/TCS3472.yaml
index d4209ea..6ec2054 100644
--- a/peripherals/TCS3472.yaml
+++ b/peripherals/TCS3472.yaml
@@ -28,31 +28,31 @@ registers:
   # Hence, the Clear register actually needs to be addressed as:
   #
   # 0b1000,0000 OR 0b0010,0000 OR 0x14 = 180 = 0xB0
-  enable:
+  Enable:
     address: 0x80
     length: 8
     title: Enable
     description: Enable specific components of the peripheral
-  clear:
+  Clear:
     address: 0xB4
     length: 16
     readWrite: 'R'
     title: Clear channel
     description: This is the ambient amount of detected light.
-  red:
+  Red:
     address: 0xB6
     length: 16
     readWrite: 'R'
     title: Red channel
     description: Red light as an int. Divide by ambient light to get scaled number.
     # Implementation note: float(light.get_red()) / light.get_clear() * 255 -> Red color value
-  green:
+  Green:
     address: 0xB8
     length: 16
     readWrite: 'R'
     title: Green channel
     description: Green light as an int. Divide by ambient light to get scaled number.
-  blue:
+  Blue:
     address: 0xBA
     length: 16
     readWrite: 'R'
@@ -62,8 +62,8 @@ registers:
 fields:
   init:
     title: Setup the device configuration
-    description: Enable RGBC and Power
-    register: '#/registers/enable'
+    description: Enable RGBC and Power.
+    register: '#/registers/Enable'
     readWrite: 'R/W'
     bitStart: 7 # The whole register
     bitEnd: 0
@@ -79,8 +79,8 @@ fields:
 functions:
   _lifecycle:
     title: Code to run when device class is constructed
-    description: Enables features on device
-    register: '#/registers/enable'
+    description: Enables features on device.
+    register: '#/registers/Enable'
     computed:
       Begin:
         variables:
diff --git a/templates/doc.md b/templates/doc.md
index 057d09a..8f5e15f 100644
--- a/templates/doc.md
+++ b/templates/doc.md
@@ -6,18 +6,103 @@ description: >
   {{info.description}}
 ---
 
+{# Create a dictionary linking a register to its associated fields #}
+{% set template = namespace(registersToFields=dict()) %}
+{% if fields %}
+{# for hierarchical display #}
+{% for key,field in fields|dictsort %}
+{% set rkey = field.register %}
+{% if rkey in template.registersToFields %}
+{% set _dummy = field.update({ 'key': key }) %}
+{{- template.registersToFields[rkey].append(field) or "" -}}
+{% else %}
+{% set _dummy = field.update({ 'key': key }) %}
+{% set _dummy = template.registersToFields.update({ rkey: [] }) %}
+{{- template.registersToFields[rkey].append(field) or "" -}}
+{% endif %}
+{% endfor %}
+{% endif %}
+
+## Device Details
+
+{% if i2c.address is iterable and i2c.address is not string %}
+* Device addresses:
+{% for address in i2c.address %}
+{{address}}{{ "," if not loop.last }}
+{% endfor %}
+{% else %}
+* Device address {{ i2c.address }}
+{% endif %}
+* Address type {{ i2c.addressType }}
+{% if i2c.endian == 'little' %}
+* Little Endian
+{% endif %}
+
 ## Registers
 {% for key,register in registers|dictsort %}
 
-### {{ register.title }}
+### {{ key }}
+**{{ register.title }}**
+* Address {{register.address}}
+* {{register.length}}-bytes
+{% if register.readWrite == "R" %}
+* Read-only
+{% endif %}
+{% if register.readWrite == "W" %}
+* Write-only
+{% endif %}
+{% if register.readWrite == "n" %}
+* Inaccessible
+{% endif %}
+{% if register.signed %}
+* Signed value
+{% endif %}
+
 {{ register.description }}
 {% endfor %}
 
+{% if fields %}
+## Fields
+{% for key in template.registersToFields.keys() %}
+{% set register = template.registersToFields[key] %}
+{% for field in register %}
+### {{ key }}/{{field.key}}
+**{{ field.title }}**
+
+{% if field.bitStart == field.bitEnd %}
+* Bit {{field.bitStart}}
+{% else %}
+* Bits {{field.bitStart}}:{{field.bitEnd}}
+{% endif %}
+
+{% if field.enum %}
+
+#### Field values
+
+{% for key,enum in field.enum|dictsort %}
+* **{{ enum.value }}**: {{ enum.title }}
+{% endfor %}
+{% endif %}
+
+{{ field.description }}
+
+{% endfor %}
+{% endfor %}
+{% endif %}
+
+{% if functions %}
+## Functions
+
+{% for key,function in functions|dictsort %}
+* **{{key}}**: {{function.description}}
+{% endfor %}
+{% endif %}
+
 ## License
-Licensed under [{{ info.license.name }}](https://spdx.org/licenses/{{ info.license.name }}.html#licenseText).
 
-_{{ info.title }} version {{ info.version }}_
+_{{ info.title }} version {{ info.version }}. Generated from Cyanobyte Codegen version {{ version }}._
 
-_Based on Cyanobyte spec version {{cyanobyte}}_
+Contact [{{ info.contact.name }}](mailto:{{ info.contact.email }}).
 
-_Generated from Cyanobyte Codegen version {{ version }}_
+Copyright {{info.copyright.name}} {{info.copyright.date}}. Published under
+[{{ info.license.name }}](https://spdx.org/licenses/{{ info.license.name }}.html#licenseText).


Test patch:
diff --git a/test/sampleData/markdown/ADS1015.md b/test/sampleData/markdown/ADS1015.md
index eb84995..00b41c6 100644
--- a/test/sampleData/markdown/ADS1015.md
+++ b/test/sampleData/markdown/ADS1015.md
@@ -6,19 +6,108 @@ description: >
   Texas Instruments Analog-Digital Converter
 ---
 
+
+## Device Details
+
+* Device address 73
+* Address type 7-bit
+* Little Endian
+
 ## Registers
 
-### ADC config
-Describes the specifics of the sensing implementation
+### Config
+**ADC config**
+* Address 1
+* 16-bytes
+
+Defines sensing implementation and options.
+
+### Conversion
+**ADC Value**
+* Address 0
+* 16-bytes
+* Read-only
+
+Contains the result of the last conversion.
+
+## Fields
+### #/registers/Config/Channel
+**Channel to read**
+
+* Bits 14:12
+
+
+#### Field values
+
+* **0**: Channel 1
+* **1**: Channel 2
+* **2**: Channel 3
+* **3**: Channel 4
+
+Sets the channel for reading analog voltage.
+
+
+### #/registers/Config/DeviceOperatingMode
+**Operating mode**
+
+* Bit 8
+
+
+#### Field values
+
+* **0**: Continuous Conversion
+* **1**: Single-shot or power-down state
+
+Controls the operating mode for reading analog voltage.
+
+
+### #/registers/Config/ProgrammableGain
+**Programmable gain**
+
+* Bits 11:9
+
+
+#### Field values
+
+* **5**: Plus/minus 0.256V
+* **4**: Plus/minus 0.512V
+* **3**: Plus/minus 1.024V
+* **2**: Plus/minus 2.048V
+* **1**: Plus/minus 4.096V
+* **0**: Plus/minus 6.144V
+
+Sets the programmable gain for reading analog voltage in voltage.
+
+
+### #/registers/Config/SampleRate
+**Sample rate**
+
+* Bits 7:5
+
+
+#### Field values
+
+* **0**: 128 samples/second
+* **4**: 1600 samples/second
+* **5**: 2400 samples/second
+* **1**: 250 samples/second
+* **6**: 3300 samples/second
+* **2**: 490 samples/second
+* **3**: 920 samples/second
+
+Sets the sample read in samples-per-second for reading analog voltage.
+
+
+
+## Functions
 
-### ADC Value
-Conversion register contains the result of the last conversion
+* **analog**: Reads the analog voltage in Volts.
 
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_ADS1015 version 0.1.0_
+_ADS1015 version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2019. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/BH1750FVI.md b/test/sampleData/markdown/BH1750FVI.md
index a4bb996..a2c1c29 100644
--- a/test/sampleData/markdown/BH1750FVI.md
+++ b/test/sampleData/markdown/BH1750FVI.md
@@ -6,46 +6,106 @@ description: >
   Rohm Light Sensor
 ---
 
+
+## Device Details
+
+* Device addresses:
+35,
+92
+* Address type 7-bit
+
 ## Registers
 
-### Continously H-Resolution Mode2
+### ContinuousHRes2Mode
+**Continously High-Resolution Mode 2**
+* Address 17
+* 0-bytes
+* Write-only
+
 Start measurement at 0.5lx resolution. Typically 120ms.
 
-### Continuously H-Resolution Mode
+### ContinuousHResMode
+**Continuously High-Resolution Mode**
+* Address 16
+* 0-bytes
+* Write-only
+
 Start measurement at 1lx resolution. Typically 120ms.
 
-### Continuously L-Resolution Mode
+### ContinuouslyLResMode
+**Continuously Low-Resolution Mode**
+* Address 19
+* 0-bytes
+* Write-only
+
 Start measurement at 4lx resolution. Typically 16ms.
 
-### One Time H-Resolution Mode2
+### OnceHRes2Mode
+**One Time High-Resolution Mode2**
+* Address 33
+* 0-bytes
+* Write-only
+
 Start measurement at 0.5lx resolution. Typically 120ms.
 Power Down after measurement.
 
 
-### One Time H-Resolution Mode
+### OnceHResMode
+**One Time High-Resolution Mode**
+* Address 32
+* 0-bytes
+* Write-only
+
 Start measurement at 1lx resolution. Typically 120ms.
 Power Down after measurement.
 
 
-### One Time L-Resolution Mode
+### OnceLResMode
+**One Time Low-Resolution Mode**
+* Address 35
+* 0-bytes
+* Write-only
+
 Start measurement at 4lx resolution. Typically 16ms.
 Power Down after measurement.
 
 
-### Power Down
-No active state
+### PowerDown
+**Power Down**
+* Address 0
+* 0-bytes
+* Write-only
+
+State when the device is not active.
 
-### Power On
-Waiting for measurement command
+### PowerOn
+**Power On**
+* Address 1
+* 0-bytes
+* Write-only
+
+State when device is on and waiting measurement command.
 
 ### Reset
+**Reset**
+* Address 7
+* 0-bytes
+* Write-only
+
 Reset data register value. Not accepted in Power Down mode.
 
+
+## Functions
+
+* **_lifecycle**: Sends a POWER ON cmd to device.
+* **command**: Commands that can be sent to the device.
+* **read**: Read light intensity from device.
+
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_BH1750FVI version 0.1.0_
+_BH1750FVI version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2020. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/BMP180.md b/test/sampleData/markdown/BMP180.md
index 05aedb9..94510f3 100644
--- a/test/sampleData/markdown/BMP180.md
+++ b/test/sampleData/markdown/BMP180.md
@@ -6,49 +6,120 @@ description: >
   Bosch Digital Temperature / Pressure Sensor
 ---
 
+
+## Device Details
+
+* Device address 119
+* Address type 7-bit
+
 ## Registers
 
-### Register to write commands
-Register stores what the measurement type should be
+### Control
+**Command register.**
+* Address 244
+* 8-bytes
+* Write-only
+
+Stores the current measurement type.
+
+### PressureCalAC1
+**Pressure calibration AC1**
+* Address 170
+* 16-bytes
+* Read-only
+
+Constant register for pressure measurement calibration.
+
+### PressureCalAC2
+**Pressure calibration AC2**
+* Address 172
+* 16-bytes
+* Read-only
+
+Constant register for pressure measurement calibration.
+
+### PressureCalVB1
+**Pressure calibration VB1**
+* Address 182
+* 16-bytes
+* Read-only
+
+Constant register for pressure measurement calibration.
+
+### PressureCalVB2
+**Pressure calibration VB2**
+* Address 184
+* 16-bytes
+* Read-only
+
+Constant register for pressure measurement calibration.
+
+### Result
+**Measurement results**
+* Address 246
+* 16-bytes
+* Read-only
+
+Stores the most recent measurement result.
+
+### TempCal3
+**Temperature calibration 3**
+* Address 174
+* 16-bytes
+* Read-only
+
+Third constant register for temperature measurement calibration.
+
+### TempCal4
+**Temperature calibration 4**
+* Address 176
+* 16-bytes
+* Read-only
+
+Fourth constant register for temperature measurement calibration.
 
-### Pressure calibration AC1
-For calibration
+### TempCal5
+**Temperature calibration 5**
+* Address 178
+* 16-bytes
+* Read-only
 
-### Pressure calibration AC2
-For calibration
+Fifth constant register for temperature measurement calibration.
 
-### Pressure calibration VB1
-For calibration
+### TempCal6
+**Temperature calibration 6**
+* Address 180
+* 16-bytes
+* Read-only
 
-### Pressure calibration VB2
-For calibration
+Sixth constant register for temperature measurement calibration.
 
-### Register that stores measurement results
-Register stores most recent measurement result
+### TempCalMC
+**Temperature calibration MC**
+* Address 188
+* 16-bytes
+* Read-only
 
-### Temperature calibration 3
-For calibration
+Constant register for temperature measurement calibration.
 
-### Temperature calibration 4
-For calibration
+### TempCalMD
+**Temperature calibration MD**
+* Address 190
+* 16-bytes
+* Read-only
 
-### Temperature calibration 5
-For calibration
+Constant register for temperature measurement calibration.
 
-### Temperature calibration 6
-For calibration
 
-### Temperature calibration MC
-For calibration
+## Functions
 
-### Temperature calibration MD
-For calibration
+* **temperature**: Reads the temperature as a raw value or in Celsius.
 
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_BMP180 version 0.1.0_
+_BMP180 version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2020. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/BMP280.md b/test/sampleData/markdown/BMP280.md
index 7f202bf..f4fe48b 100644
--- a/test/sampleData/markdown/BMP280.md
+++ b/test/sampleData/markdown/BMP280.md
@@ -6,67 +6,179 @@ description: >
   Bosch Digital Pressure Sensor
 ---
 
+
+## Device Details
+
+* Device address 119
+* Address type 7-bit
+
 ## Registers
 
-### Digital Pressure Compensation 1
-Used for Pascals conversion
+### DigP1
+**Digital Pressure Compensation 1**
+* Address 142
+* 16-bytes
+* Read-only
+
+Compensation register used for Pascals conversion.
+
+### DigP2
+**Digital Pressure Compensation 2**
+* Address 144
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP3
+**Digital Pressure Compensation 3**
+* Address 146
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP4
+**Digital Pressure Compensation 4**
+* Address 148
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP5
+**Digital Pressure Compensation 5**
+* Address 150
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP6
+**Digital Pressure Compensation 6**
+* Address 152
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP7
+**Digital Pressure Compensation 7**
+* Address 154
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP8
+**Digital Pressure Compensation 8**
+* Address 156
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigP9
+**Digital Pressure Compensation 9**
+* Address 158
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for Pascals conversion.
+
+### DigT1
+**Digital Temperature Compensation 1**
+* Address 136
+* 16-bytes
+* Read-only
+
+Compensation register used for temperature measurement result.
+
+### DigT2
+**Digital Temperature Compensation 2**
+* Address 138
+* 16-bytes
+* Read-only
+* Signed value
+
+Compensation register used for temperature measurement result.
 
-### Digital Pressure Compensation 2
-Used for Pascals conversion
+### DigT3
+**Digital Temperature Compensation 3**
+* Address 140
+* 16-bytes
+* Read-only
+* Signed value
 
-### Digital Pressure Compensation 3
-Used for Pascals conversion
+Compensation register used for temperature measurement result.
 
-### Digital Pressure Compensation 4
-Used for Pascals conversion
+### PressureLsb
+**Pressure LSB**
+* Address 248
+* 8-bytes
+* Read-only
 
-### Digital Pressure Compensation 5
-Used for Pascals conversion
+Middle-significant bit of pressure measurement result.
 
-### Digital Pressure Compensation 6
-Used for Pascals conversion
+### PressureMsb
+**Pressure MSB**
+* Address 247
+* 8-bytes
+* Read-only
 
-### Digital Pressure Compensation 7
-Used for Pascals conversion
+Most-significant bit of pressure measurement result.
 
-### Digital Pressure Compensation 8
-Used for Pascals conversion
+### PressureXlsb
+**Pressure XLSB**
+* Address 249
+* 8-bytes
+* Read-only
 
-### Digital Pressure Compensation 9
-Used for Pascals conversion
+Least-significant bit of pressure measurement result.
 
-### Digital Temperature Compensation 1
-Used for Celcius conversion
+### TempLsb
+**Temperature LSB**
+* Address 251
+* 8-bytes
+* Read-only
 
-### Digital Temperature Compensation 2
-Used for Celcius conversion
+Middle-significant bit of temperature measurement result.
 
-### Digital Temperature Compensation 3
-Used for Celcius conversion
+### TempMsb
+**Temperature MSB**
+* Address 250
+* 8-bytes
+* Read-only
 
-### Pressure LSB
-Part 2 of Pressure
+Most-significant bit of temperature measurement result.
 
-### Pressure MSB
-Part 1 of Pressure
+### TempXlsb
+**Temperature XLSB**
+* Address 252
+* 8-bytes
+* Read-only
 
-### Pressure XLSB
-Part 3 of Pressure
+Least-significant bit of temperature measurement result.
 
-### Temperature LSB
-Part 2 of temperature
 
-### Temperature MSB
-Part 1 of temperature
+## Functions
 
-### Temperature XLSB
-Final part of temperature
+* **pressure**: Reads the atmospheric pressure as a raw value or in hPa.
+* **temperature**: Reads the temperature as a raw value or in Celsius.
 
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_BMP280 version 0.1.0_
+_BMP280 version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2019. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/LSM303D.md b/test/sampleData/markdown/LSM303D.md
index 67711b9..f51511a 100644
--- a/test/sampleData/markdown/LSM303D.md
+++ b/test/sampleData/markdown/LSM303D.md
@@ -6,49 +6,121 @@ description: >
   STMicroelectronics accelerometer and magnetometer
 ---
 
+
+## Device Details
+
+* Device address 29
+* Address type 7-bit
+
 ## Registers
 
-### Accelerometer X
-Raw accelerometer data on X plane
+### AccelerometerX_High
+**Accelerometer X-Axis MSB**
+* Address 169
+* 8-bytes
+* Read-only
+
+Most-significant bits for raw accelerometer data on X plane.
+
+### AccelerometerX_Low
+**Accelerometer X-Axis LSB**
+* Address 168
+* 8-bytes
+* Read-only
+
+Least-significant bits for raw accelerometer data on X plane.
+
+### AccelerometerY_High
+**Accelerometer Y-Axis MSB**
+* Address 171
+* 8-bytes
+* Read-only
+
+Most-significant bits for raw accelerometer data on Y plane.
+
+### AccelerometerY_Low
+**Accelerometer Y-Axis LSB**
+* Address 170
+* 8-bytes
+* Read-only
+
+Least-significant bits for raw accelerometer data on Y plane.
+
+### AccelerometerZ_High
+**Accelerometer Z-Axis MSB**
+* Address 173
+* 8-bytes
+* Read-only
+
+Most-significant bits for raw accelerometer data on Z plane.
+
+### AccelerometerZ_Low
+**Accelerometer Z-Axis LSB**
+* Address 172
+* 8-bytes
+* Read-only
+
+Least-significant bits for raw accelerometer data on Z plane.
+
+### MagnetometerX_High
+**Magnetometer X-Axis MSB**
+* Address 137
+* 8-bytes
+* Read-only
+
+Most-significant bits for raw magnetometer data on X plane.
+
+### MagnetometerX_Low
+**Magnetometer X-Axis LSB**
+* Address 136
+* 8-bytes
+* Read-only
+
+Least-significant bits for raw magnetometer data on X plane.
 
-### Accelerometer X
-Raw accelerometer data on X plane
+### MagnetometerY_High
+**Magnetometer Y-Axis MSB**
+* Address 139
+* 8-bytes
+* Read-only
 
-### Accelerometer Y
-Raw accelerometer data on Y plane
+Most-significant bits for raw magnetometer data on Y plane.
 
-### Accelerometer Y
-Raw accelerometer data on Y plane
+### MagnetometerY_Low
+**Magnetometer Y-Axis LSB**
+* Address 138
+* 8-bytes
+* Read-only
 
-### Accelerometer Z
-Raw accelerometer data on Z plane
+Least-significant bits for raw magnetometer data on Y plane.
 
-### Accelerometer Z
-Raw accelerometer data on Z plane
+### MagnetometerZ_High
+**Magnetometer Z-Axis MSB**
+* Address 141
+* 8-bytes
+* Read-only
 
-### Magnetometer X
-Raw magnetometer data on X plane
+Most-significant bits for raw magnetometer data on Z plane.
 
-### Magnetometer X
-Raw magnetometer data on X plane
+### MagnetometerZ_Low
+**Magnetometer Z-Axis LSB**
+* Address 140
+* 8-bytes
+* Read-only
 
-### Magnetometer Y
-Raw magnetometer data on Y plane
+Least-significant bits for raw magnetometer data on Z plane.
 
-### Magnetometer Y
-Raw magnetometer data on Y plane
 
-### Magnetometer Z
-Raw magnetometer data on Z plane
+## Functions
 
-### Magnetometer Z
-Raw magnetometer data on Z plane
+* **acceleration**: Measures the current acceleration for each plane.
+* **orientation**: Reads the magnetic orientation for each plane and compass heading.
 
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_LSM303D version 0.1.0_
+_LSM303D version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2019. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/MCP4725.md b/test/sampleData/markdown/MCP4725.md
index 98b51a4..0709560 100644
--- a/test/sampleData/markdown/MCP4725.md
+++ b/test/sampleData/markdown/MCP4725.md
@@ -3,28 +3,65 @@ title: "MCP4725"
 linkTitle: "MCP4725"
 weight: 4
 description: >
-  Microchip 4725 Digital-to-Analog Converter
+  Microchip Digital-to-Analog Converter
 ---
 
+
+## Device Details
+
+* Device address 98
+* Address type 7-bit
+* Little Endian
+
 ## Registers
 
 ### EEPROM
+**EEPROM**
+* Address 96
+* 12-bytes
+
 If EEPROM is set, the saved voltage output will
 be loaded from power-on.
 
 
-### Output voltage
-VOut = (Vcc * value) / 4096
+### VOut
+**Output voltage**
+* Address 64
+* 12-bytes
+
+Sets the output voltage relative to Vcc.
+VOut = (Vcc * value) / 4096.
 The output is a range between 0 and Vcc with
 steps of Vcc/4096.
 In a 3.3v system, each step is 800 microvolts.
 
 
+## Fields
+### #/registers/EEPROM/digitalOut
+**Digital (binary) output**
+
+* Bits 12:0
+
+
+#### Field values
+
+* **0**: Ground
+* **4095**: Vcc (full power)
+
+Set output as either fully on or fully off.
+
+
+
+## Functions
+
+* **getVOut**: Read VOut from EEPROM as a function of Vcc.
+* **setVOut**: Set VOut as a function of Vcc.
+
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_MCP4725 version 0.1.0_
+_MCP4725 version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2019. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/MCP9808.md b/test/sampleData/markdown/MCP9808.md
index 9e6038d..1df14eb 100644
--- a/test/sampleData/markdown/MCP9808.md
+++ b/test/sampleData/markdown/MCP9808.md
@@ -3,12 +3,30 @@ title: "MCP9808"
 linkTitle: "MCP9808"
 weight: 4
 description: >
-  This is a test description
+  Microchip Temperature Sensor
 ---
 
+
+## Device Details
+
+* Device addresses:
+24,
+25,
+26,
+27,
+28,
+29,
+30,
+31
+* Address type 7-bit
+
 ## Registers
 
-### Configuration Register
+### configuration
+**Configuration Register**
+* Address 1
+* 16-bytes
+
 The MCP9808 has a 16-bit Configuration register (CONFIG) that
 allows the user to set various functions for a robust temperature
 monitoring system.
@@ -22,11 +40,49 @@ and Alert output polarity and mode (Comparator Output or Interrupt
 Output mode) are user-configurable.
 
 
+## Fields
+### #/registers/configuration/limitHysteresis
+**TUPPER and TLOWER Limit Hysteresis bits**
+
+* Bits 10:9
+
+
+#### Field values
+
+* **0**: 0°C (power-up default)
+* **1**: +1.5°C
+* **2**: +3.0°C
+* **3**: +6.0°C
+
+This bit can not be altered when either of the Lock bits are set
+(bit 6 and bit 7). This bit can be programmed in Shutdown mode.
+
+
+### #/registers/configuration/shutdownMode
+**Shutdown Mode bit**
+
+* Bit 8
+
+
+#### Field values
+
+* **0**: Continuous conversion (power-up default)
+* **1**: Shutdown (Low-Power mode)
+
+In shutdown, all power-consuming activities are disabled, though
+all registers can be written to or read. This bit cannot be set
+to ‘1’ when either of the Lock bits is set (bit 6 and bit 7).
+However, it can be cleared to ‘0’ for continuous conversion while
+locked.
+
+
+
+
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_MCP9808 version 0.1.0_
+_MCP9808 version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2019. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file
diff --git a/test/sampleData/markdown/TCS3472.md b/test/sampleData/markdown/TCS3472.md
index 9a51e57..9571557 100644
--- a/test/sampleData/markdown/TCS3472.md
+++ b/test/sampleData/markdown/TCS3472.md
@@ -6,28 +6,77 @@ description: >
   Color Light-to-Digital Converter with IR Filter
 ---
 
+
+## Device Details
+
+* Device address 41
+* Address type 7-bit
+
 ## Registers
 
-### Blue channel
+### Blue
+**Blue channel**
+* Address 186
+* 16-bytes
+* Read-only
+
 Blue light as an int. Divide by ambient light to get scaled number.
 
-### Clear channel
+### Clear
+**Clear channel**
+* Address 180
+* 16-bytes
+* Read-only
+
 This is the ambient amount of detected light.
 
 ### Enable
+**Enable**
+* Address 128
+* 8-bytes
+
 Enable specific components of the peripheral
 
-### Green channel
+### Green
+**Green channel**
+* Address 184
+* 16-bytes
+* Read-only
+
 Green light as an int. Divide by ambient light to get scaled number.
 
-### Red channel
+### Red
+**Red channel**
+* Address 182
+* 16-bytes
+* Read-only
+
 Red light as an int. Divide by ambient light to get scaled number.
 
+## Fields
+### #/registers/Enable/init
+**Setup the device configuration**
+
+* Bits 7:0
+
+
+#### Field values
+
+* **1**: Power
+* **2**: Color
+
+Enable RGBC and Power.
+
+
+## Functions
+
+* **_lifecycle**: Enables features on device.
+
 ## License
-Licensed under [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
 
-_TCS3472 version 0.1.0_
+_TCS3472 version 0.1.0. Generated from Cyanobyte Codegen version 0.0.2._
 
-_Based on Cyanobyte spec version 0.1.0_
+Contact [Nick Felker](mailto:felker@google.com).
 
-_Generated from Cyanobyte Codegen version 0.1.0_
\ No newline at end of file
+Copyright Google Inc. 2019. Published under
+[Apache-2.0](https://spdx.org/licenses/Apache-2.0.html#licenseText).
\ No newline at end of file