summaryrefslogtreecommitdiff
path: root/atmel-samd/asf
diff options
context:
space:
mode:
authorScott Shawcroft <scott@chickadee.tech>2016-08-23 16:47:53 -0700
committerScott Shawcroft <scott@chickadee.tech>2016-08-23 16:47:53 -0700
commit9485634d41369e896a0ef0f7504f2195b68679e7 (patch)
treee97b3a81e8e4160ed7d03afdbd462880995422e1 /atmel-samd/asf
parent8f26d181c30f8d371a900355a6f9edfab29c8fbe (diff)
Add support for REPL on Arduino Zero through EDBG via UART.
Diffstat (limited to 'atmel-samd/asf')
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_state_diagram.svg533
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_topology.svg351
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_read.svg1037
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_write.svg1031
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_common.h613
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master.h629
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master_interrupt.h214
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c1050
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c762
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave.c745
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave_interrupt.c434
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master.c881
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master_interrupt.c670
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave.c693
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave_interrupt.c434
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave.h753
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave_interrupt.h215
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/sercom.c296
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/sercom.h118
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.c141
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.h72
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/sercom_pinout.h526
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi/module_config/conf_spi.h55
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi/spi.c1265
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi/spi.h1807
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.c741
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.h190
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi.h55
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi_master_vec.h68
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c588
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h692
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/usart/docimg/usart_frame.svg272
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/usart/usart.c817
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/usart/usart.h1593
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.c666
-rw-r--r--atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.h177
-rw-r--r--atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c2
-rw-r--r--atmel-samd/asf/sam0/utils/syscalls/gcc/syscalls.c8
38 files changed, 21189 insertions, 5 deletions
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_state_diagram.svg b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_state_diagram.svg
new file mode 100644
index 000000000..4bd4175a0
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_state_diagram.svg
@@ -0,0 +1,533 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2985"
+ version="1.1"
+ inkscape:version="0.48.2 r9819"
+ width="380.12842"
+ height="320.95972"
+ xml:space="preserve"
+ sodipodi:docname="Sercom_I2C_Bus_State_State_Diagram.svg"><metadata
+ id="metadata2991"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs2989"><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3001"><path
+ d="m 0,762.9 612,0 0,0.53998 -612,0 L 0,762.9 z"
+ id="path3003"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3011"><path
+ d="m 611.76,757.86 0.23999,0 0,5.34 -0.23999,0 0,-5.34 z"
+ id="path3013"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3021"><path
+ d="m 0,757.86 612,0 0,0.54004 -612,0 0,-0.54004 z"
+ id="path3023"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3031"><path
+ d="m 0,758.1 0.29999,0 0,5.34 -0.29999,0 0,-5.34 z"
+ id="path3033"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3043"><path
+ d="m 0,791.7 612,0 0,0.29999 -612,0 L 0,791.7 z"
+ id="path3045"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3053"><path
+ d="m 611.76,762.9 0.23999,0 0,29.1 -0.23999,0 0,-29.1 z"
+ id="path3055"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3063"><path
+ d="m 0,762.9 612,0 0,0.53998 -612,0 L 0,762.9 z"
+ id="path3065"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3073"><path
+ d="m 0,763.14 0.29999,0 0,28.86 L 0,792 0,763.14 z"
+ id="path3075"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3105"><path
+ d="m 35.28,48.42 50.22,0 0,-12.48 -50.22,0 0,12.48 z"
+ clip-rule="evenodd"
+ id="path3107"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3111"><path
+ d="m 0,792.03 612,0 0,-792 -612,0 0,792 z"
+ id="path3113"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3321"><path
+ d="m 161.64,724.98 324.72,0 0,-271.02 -324.72,0 0,271.02 z"
+ clip-rule="evenodd"
+ id="path3323"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3327"><path
+ d="m 109.8,726.84 428.46,0 0,-274.74 -428.46,0 0,274.74 z"
+ clip-rule="evenodd"
+ id="path3329"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3333"><path
+ d="m 72,735.84 504,0 0,-503.76 -504,0 0,503.76 z"
+ clip-rule="evenodd"
+ id="path3335"
+ inkscape:connector-curvature="0" /></clipPath><clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath3339"><path
+ d="m 0,792.03 612,0 0,-792 -612,0 0,792 z"
+ id="path3341"
+ inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1230"
+ inkscape:window-height="873"
+ id="namedview2987"
+ showgrid="true"
+ inkscape:zoom="1.6066596"
+ inkscape:cx="241.9873"
+ inkscape:cy="159.0032"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="g2993"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"><inkscape:grid
+ type="xygrid"
+ id="grid3962"
+ empspacing="5"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true" /></sodipodi:namedview><g
+ id="g2993"
+ inkscape:groupmode="layer"
+ inkscape:label="SAMD20"
+ transform="matrix(1.25,0,0,-1.25,-183.91829,749.20451)"><g
+ transform="translate(179.56813,517.13011)"
+ id="g3343"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3345"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 11.82,35.04 44.58,58.56 81.48,58.5" /></g><g
+ transform="translate(183.04813,517.07011)"
+ id="g3347"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3349"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 -5.94,-8.88 -6.48,1.8 0,0" /></g><text
+ id="text3351"
+ transform="scale(0.99830575,-1.0016971)"
+ x="197.48271"
+ y="-537.51788"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3353"
+ sodipodi:role="line"
+ y="-537.51788"
+ x="197.48271 202.8923 204.69655 209.50446 211.90959 216.71907 219.12421 226.3349 230.54115 235.35063 240.16011"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">P + Timeout</tspan></text>
+
+<g
+ transform="translate(202.96813,594.41011)"
+ id="g3355"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3357"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 19.08,4.56 39.12,2.64 56.94,-5.46" /></g><g
+ transform="translate(260.62813,592.31011)"
+ id="g3359"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3361"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 4.56,-6 -3,-6 0,0" /></g><text
+ id="text3363"
+ transform="scale(0.99830575,-1.0016971)"
+ x="223.32651"
+ y="-583.81927"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3365"
+ sodipodi:role="line"
+ y="-583.81927"
+ x="223.32651 229.33542 234.74501 240.1546 245.56419"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">RESET</tspan></text>
+
+<g
+ transform="translate(251.80813,384.53011)"
+ id="g3367"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3369"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C -36.66,3.84 -66.72,30.78 -74.7,66.9" /></g><g
+ transform="translate(251.14813,387.89011)"
+ id="g3371"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3373"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 9.9,-3.84 -0.36,-6.72 0,0" /></g><text
+ id="text3375"
+ transform="scale(0.99830575,-1.0016971)"
+ x="197.48271"
+ y="-420.29681"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3377"
+ sodipodi:role="line"
+ y="-420.29681"
+ x="197.48271 205.29744 208.30112 210.70624 213.1106 217.31683 219.72197 225.73088 231.73981 237.74872"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">Write ADDR</tspan><tspan
+ id="tspan3379"
+ sodipodi:role="line"
+ y="-410.71301"
+ x="214.91249 217.31683 222.72643"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">(S)</tspan></text>
+
+<g
+ transform="translate(147.22813,479.81011)"
+ id="g3381"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3383"
+ style="fill:#008000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.72,28.44 28.32,28.44 43.98,28.44 56.7,15.72 56.7,0 56.7,-15.72 43.98,-28.44 28.32,-28.44 12.72,-28.44 0,-15.72 0,0" /></g><g
+ transform="translate(147.22813,479.81011)"
+ id="g3385"
+ style="fill:#8cc63f;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3387"
+ style="fill:#8cc63f;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.72,28.44 28.32,28.44 43.98,28.44 56.7,15.72 56.7,0 56.7,-15.72 43.98,-28.44 28.32,-28.44 12.72,-28.44 0,-15.72 0,0" /></g><text
+ id="text3389"
+ transform="scale(0.99831175,-1.0016911)"
+ x="165.02673"
+ y="-481.03674"
+ style="font-size:9.60000001999999950px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;fill:#000000;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3391"
+ sodipodi:role="line"
+ y="-481.03674"
+ x="165.02673 167.43201 174.64301 180.65474"
+ style="font-size:9.60000001999999950px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none">IDLE</tspan></text>
+
+<text
+ id="text3393"
+ transform="scale(0.99830575,-1.0016971)"
+ x="163.8257"
+ y="-470.79111"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;fill:#000000;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3395"
+ sodipodi:role="line"
+ y="-470.79111"
+ x="163.8257 166.83093 171.03717 175.84665 180.0529 184.86003"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">(0b01)</tspan></text>
+
+<g
+ transform="translate(202.96813,487.13011)"
+ id="g3397"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3399"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 54.66,12.54 111.42,12.96 166.26,1.26" /></g><g
+ transform="translate(369.16813,491.93011)"
+ id="g3401"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3403"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 5.82,-4.8 -1.5,-6.6 0,0" /></g><text
+ id="text3405"
+ transform="scale(0.99830575,-1.0016971)"
+ x="287.03442"
+ y="-485.22662"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3407"
+ y="-485.22662"
+ x="287.03442"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">S</tspan></text>
+
+<g
+ transform="translate(374.02813,479.81011)"
+ id="g3409"
+ style="fill:#f99d31;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3411"
+ style="fill:#f99d31;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.66,28.44 28.38,28.44 43.98,28.44 56.7,15.72 56.7,0 56.7,-15.72 43.98,-28.44 28.38,-28.44 12.66,-28.44 0,-15.72 0,0" /></g><g
+ transform="translate(374.02813,479.81011)"
+ id="g3413"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3415"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.66,28.44 28.38,28.44 43.98,28.44 56.7,15.72 56.7,0 56.7,-15.72 43.98,-28.44 28.38,-28.44 12.66,-28.44 0,-15.72 0,0" /></g><text
+ id="text3417"
+ transform="scale(0.99831175,-1.0016911)"
+ x="389.80621"
+ y="-481.03674"
+ style="font-size:9.60000001999999950px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000000000000002;stroke-miterlimit:4;stroke-dasharray:none;fill:#000000"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3419"
+ sodipodi:role="line"
+ y="-481.03674"
+ x="389.80621 397.01337 404.22052 410.89874"
+ style="font-size:9.60000001999999950px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000000000000002;stroke-miterlimit:4;stroke-dasharray:none">BUSY</tspan></text>
+
+<text
+ id="text3421"
+ transform="scale(0.99830575,-1.0016971)"
+ x="391.01059"
+ y="-470.79111"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001000000002;stroke-miterlimit:4;stroke-dasharray:none;fill:#000000"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3423"
+ sodipodi:role="line"
+ y="-470.79111"
+ x="391.01059 394.01584 398.22208 403.09174 407.29797 412.1051"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001000000002;stroke-miterlimit:4;stroke-dasharray:none">(0b11)</tspan></text>
+
+<g
+ transform="translate(212.02813,470.51011)"
+ id="g3425"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3427"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 53.82,-10.98 109.38,-10.32 162.96,1.92" /></g><g
+ transform="translate(213.52813,473.63011)"
+ id="g3429"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3431"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 -10.56,-1.2 -1.38,-6.6 0,0" /></g><text
+ id="text3433"
+ transform="scale(0.99830575,-1.0016971)"
+ x="266.59982"
+ y="-467.7962"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3435"
+ sodipodi:role="line"
+ y="-467.7962"
+ x="266.59982 272.0094 274.41455 279.22244 281.0267 285.83618 288.2413 295.452 299.65823 304.46774 309.27719"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">P + Timeout</tspan></text>
+
+<g
+ transform="translate(260.62813,570.83011)"
+ id="g3437"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3439"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.72,28.44 28.32,28.44 44.04,28.44 56.7,15.72 56.7,0 56.7,-15.72 44.04,-28.44 28.32,-28.44 12.72,-28.44 0,-15.72 0,0" /></g><g
+ transform="translate(260.62813,570.83011)"
+ id="g3441"
+ style="stroke-width:0.40000000000000002;stroke-miterlimit:4;stroke-dasharray:none;fill:#dcdcdc"><path
+ inkscape:connector-curvature="0"
+ id="path3443"
+ style="fill:#dcdcdc;stroke:#000000;stroke-width:0.40000000000000002;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.72,28.44 28.32,28.44 44.04,28.44 56.7,15.72 56.7,0 56.7,-15.72 44.04,-28.44 28.32,-28.44 12.72,-28.44 0,-15.72 0,0" /></g><text
+ id="text3445"
+ transform="scale(0.99831175,-1.0016911)"
+ x="263.59314"
+ y="-571.78314"
+ style="font-size:9.60000001999999950px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3447"
+ sodipodi:role="line"
+ y="-571.78314"
+ x="263.59314 270.80414 278.01514 285.22617 292.43716 299.65103 308.66815"
+ style="font-size:9.60000001999999950px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none">UNKNOWN</tspan></text>
+
+<text
+ id="text3449"
+ transform="scale(0.99830575,-1.0016971)"
+ x="277.41815"
+ y="-561.53711"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3451"
+ sodipodi:role="line"
+ y="-561.53711"
+ x="277.41815 280.4234 284.62964 289.43912 293.64536 298.45248"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">(0b00)</tspan></text>
+
+<g
+ transform="translate(260.62813,388.79011)"
+ id="g3453"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3455"
+ style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.72,28.44 28.32,28.44 44.04,28.44 56.7,15.72 56.7,0 56.7,-15.72 44.04,-28.44 28.32,-28.44 12.72,-28.44 0,-15.72 0,0" /></g><g
+ transform="translate(260.62813,388.79011)"
+ id="g3457"
+ style="fill:#cdeae8;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3459"
+ style="fill:#cdeae8;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 0,15.72 12.72,28.44 28.32,28.44 44.04,28.44 56.7,15.72 56.7,0 56.7,-15.72 44.04,-28.44 28.32,-28.44 12.72,-28.44 0,-15.72 0,0" /></g><text
+ id="text3461"
+ transform="scale(0.99831175,-1.0016911)"
+ x="270.80533"
+ y="-390.23019"
+ style="font-size:9.60000001999999950px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3463"
+ sodipodi:role="line"
+ y="-390.23019"
+ x="270.80533 278.0192 287.03632 294.24734 300.85822"
+ style="font-size:9.60000001999999950px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none">OWNER</tspan></text>
+
+<text
+ id="text3465"
+ transform="scale(0.99830575,-1.0016971)"
+ x="277.41815"
+ y="-380.04514"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3467"
+ sodipodi:role="line"
+ y="-380.04514"
+ x="277.41815 280.4234 284.62964 289.43912 293.64536 298.45248"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">(0b10)</tspan></text>
+
+<g
+ transform="translate(399.46813,442.37011)"
+ id="g3469"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3471"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C -11.22,-36.12 -45,-60.3 -82.68,-59.22" /></g><g
+ transform="translate(395.98813,442.37011)"
+ id="g3473"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3475"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 5.7,9 6.54,-1.62 0,0" /></g><text
+ id="text3477"
+ transform="scale(0.99830575,-1.0016971)"
+ x="338.72202"
+ y="-419.69794"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3479"
+ sodipodi:role="line"
+ y="-419.69794"
+ x="338.72202 344.73093 347.73462 352.5441 354.94922 357.35358 360.35724 364.56348 366.96783 369.37296 374.18243"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">Arbitration</tspan><tspan
+ id="tspan3481"
+ sodipodi:role="line"
+ y="-410.11414"
+ x="350.74219 355.55167 360.36115 364.56738"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">Lost</tspan></text>
+
+<g
+ transform="translate(209.44813,463.55011)"
+ id="g3483"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3485"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 23.58,-13.68 44.7,-31.32 62.4,-52.08" /></g><g
+ transform="translate(208.54813,460.19011)"
+ id="g3487"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3489"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 -7.14,7.8 3.3,5.88 0,0" /></g><g
+ transform="translate(294.64813,360.89011)"
+ id="g3491"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3493"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="m 0,0 c 4.5,-3.12 5.64,-9.36 2.52,-13.92 -3.12,-4.5 -9.3,-5.64 -13.86,-2.52 -3.78,2.64 -5.28,7.5 -3.66,11.82" /></g><g
+ transform="translate(276.52813,357.71011)"
+ id="g3495"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3497"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 6.78,3.18 5.28,-4.14 0,0" /></g><text
+ id="text3499"
+ transform="scale(0.99830575,-1.0016971)"
+ x="247.36723"
+ y="-435.93027"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3501"
+ sodipodi:role="line"
+ y="-435.93027"
+ x="247.36723 253.37614 258.18564 265.39633 272.60703 276.81329 281.62277 286.43222 288.83737"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">Command P</tspan><tspan
+ id="tspan3503"
+ sodipodi:role="line"
+ y="-351.17404"
+ x="304.46368 312.27841 315.28207 317.68723 320.09155 324.29779 326.70294 332.71185 338.72076 344.72968 350.73862 351.94196 354.34631 359.75589 362.75958"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">Write ADDR (Sr)</tspan></text>
+
+<g
+ transform="translate(430.12813,485.51011)"
+ id="g3505"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3507"
+ style="fill:none;stroke:#000000;stroke-width:0.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ d="M 0,0 C 3.18,5.4 10.08,7.2 15.42,4.08 20.76,0.9 22.62,-6 19.5,-11.4 17.04,-15.6 12.3,-17.7 7.56,-16.8" /></g><g
+ transform="translate(436.42813,465.47011)"
+ id="g3509"
+ style="stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"><path
+ inkscape:connector-curvature="0"
+ id="path3511"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.4;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 0,0 -6.3,8.64 3.9,5.52 0,0" /></g><text
+ id="text3513"
+ transform="scale(0.99830575,-1.0016971)"
+ x="438.55115"
+ y="-494.27127"
+ style="font-size:9.60000012000000070px;-inkscape-font-specification:Arial;font-family:Arial;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none"
+ sodipodi:linespacing="125%"><tspan
+ id="tspan3515"
+ sodipodi:role="line"
+ y="-494.27127"
+ x="438.55115 443.95996"
+ style="font-size:9.60000012000000070px;font-variant:normal;font-weight:normal;font-stretch:normal;writing-mode:lr;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Arial;-inkscape-font-specification:Arial;font-style:normal;text-anchor:start;text-align:start;line-height:125%;stroke-width:0.40000001;stroke-miterlimit:4;stroke-dasharray:none">Sr</tspan></text>
+
+</g></svg>
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_topology.svg b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_topology.svg
new file mode 100644
index 000000000..80df58f30
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/bus_topology.svg
@@ -0,0 +1,351 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 bus_topology.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="7.30346in"
+ height="2.76924in" viewBox="0 0 525.849 199.385" xml:space="preserve" color-interpolation-filters="sRGB" class="st13">
+ <v:documentProperties v:langID="1033" v:metric="true" v:viewMarkup="false"/>
+
+ <style type="text/css">
+ <![CDATA[
+ .st1 {fill:#ffffff;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st2 {fill:#000000;font-family:Arial;font-size:1.00001em;font-weight:bold}
+ .st3 {font-size:1em}
+ .st4 {fill:#ffffff;stroke:#000000;stroke-dasharray:1.68,1.2;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st5 {stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st6 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72}
+ .st7 {fill:#000000;font-family:Arial;font-size:0.833336em}
+ .st8 {baseline-shift:-32.4947%;font-size:0.649894em}
+ .st9 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st10 {stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.2}
+ .st11 {baseline-shift:-32.4941%;font-size:0.649882em}
+ .st12 {fill:#000000;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st13 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+ <title>Page-1</title>
+ <v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
+ v:shadowOffsetY="-8.50394"/>
+ <g id="group1-1" transform="translate(0.24,-0.72)" v:mID="1" v:groupContext="group">
+ <title>Sheet.1</title>
+ <g id="shape2-2" v:mID="2" v:groupContext="shape" transform="translate(155.906,-113.386)">
+ <title>Box.448</title>
+ <desc>I2C DEVICE #1</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="42.5197" cy="171.039" width="85.04" height="56.6929"/>
+ <rect x="0" y="142.692" width="85.0394" height="56.6929" class="st1"/>
+ <text x="9.18" y="167.44" class="st2" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>I2C DEVICE <tspan
+ x="35.85" dy="1.2em" class="st3">#</tspan>1</text> </g>
+ <g id="shape3-6" v:mID="3" v:groupContext="shape" transform="translate(180.709,-70.8661)">
+ <title>Box.450</title>
+ <path d="M0 199.39 L7.09 199.39 L7.09 171.04 L0 171.04 L0 199.39 Z" class="st4"/>
+ </g>
+ <g id="shape4-8" v:mID="4" v:groupContext="shape" transform="translate(209.055,-70.8661)">
+ <title>Box.451</title>
+ <path d="M0 199.39 L7.09 199.39 L7.09 171.04 L0 171.04 L0 199.39 Z" class="st4"/>
+ </g>
+ <g id="shape5-10" v:mID="5" v:groupContext="shape" transform="translate(184.252,-99.2126)">
+ <title>Bottom to top 1</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape6-13" v:mID="6" v:groupContext="shape" transform="translate(212.598,-99.2126)">
+ <title>Bottom to top 1.453</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape7-16" v:mID="7" v:groupContext="shape" transform="translate(212.598,-56.6929)">
+ <title>Bottom to top 1.454</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape8-19" v:mID="8" v:groupContext="shape" transform="translate(184.252,-28.3465)">
+ <title>Bottom to top 1.455</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 156.87 L0 178.13 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape9-22" v:mID="9" v:groupContext="shape" transform="translate(109.843,-127.559)">
+ <title>Box.449</title>
+ <rect x="0" y="171.039" width="7.08661" height="28.3465" class="st1"/>
+ </g>
+ <g id="shape10-24" v:mID="10" v:groupContext="shape" transform="translate(113.386,-155.906)">
+ <title>Bottom to top 1.456</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 171.04 L0 185.21 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape11-27" v:mID="11" v:groupContext="shape" transform="translate(113.386,-56.6929)">
+ <title>Bottom to top 1.457</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 128.52 L0 163.95 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape12-30" v:mID="12" v:groupContext="shape" transform="translate(67.3228,-127.559)">
+ <title>Box.447</title>
+ <rect x="0" y="171.039" width="7.08661" height="28.3465" class="st1"/>
+ </g>
+ <g id="shape13-32" v:mID="13" v:groupContext="shape" transform="translate(70.8661,-155.906)">
+ <title>Bottom to top 1.458</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 171.04 L0 185.21 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape14-35" v:mID="14" v:groupContext="shape" transform="translate(70.8661,-28.3465)">
+ <title>Bottom to top 1.459</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 100.17 L0 149.78 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape15-38" v:mID="15" v:groupContext="shape" transform="translate(77.9528,-141.732)">
+ <title>Sheet.15</title>
+ <desc>RP</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">P</tspan></text> </g>
+ <g id="shape16-42" v:mID="16" v:groupContext="shape" transform="translate(120.472,-141.732)">
+ <title>Sheet.16</title>
+ <desc>RP</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">P</tspan></text> </g>
+ <g id="shape17-46" v:mID="17" v:groupContext="shape" transform="translate(187.795,-77.9528)">
+ <title>Sheet.17</title>
+ <desc>RS</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">S</tspan></text> </g>
+ <g id="shape18-50" v:mID="18" v:groupContext="shape" transform="translate(219.685,-77.9528)">
+ <title>Sheet.18</title>
+ <desc>RS</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">S</tspan></text> </g>
+ <g id="shape19-54" v:mID="19" v:groupContext="shape" transform="translate(-3.59712E-014,-42.5197)">
+ <title>Box.211</title>
+ <desc>SDA</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="21.2598" cy="185.212" width="42.52" height="28.3465"/>
+ <rect x="0" y="171.039" width="42.5197" height="28.3465" class="st9"/>
+ <text x="13.18" y="188.81" class="st2" v:langID="1044"><v:paragraph v:horizAlign="2"/><v:tabList/>SDA</text> </g>
+ <g id="shape20-57" v:mID="20" v:groupContext="shape" transform="translate(-3.59712E-014,-14.1732)">
+ <title>Box.465</title>
+ <desc>SCL</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="21.2598" cy="185.212" width="42.52" height="28.3465"/>
+ <rect x="0" y="171.039" width="42.5197" height="28.3465" class="st9"/>
+ <text x="14.52" y="188.81" class="st2" v:langID="1044"><v:paragraph v:horizAlign="2"/><v:tabList/>SCL</text> </g>
+ <g id="shape21-60" v:mID="21" v:groupContext="shape" transform="translate(42.5197,-56.6929)">
+ <title>Side to side 1</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 199.39 L240.94 199.39 L481.89 199.39" class="st10"/>
+ </g>
+ <g id="shape22-63" v:mID="22" v:groupContext="shape" transform="translate(42.5197,-28.3465)">
+ <title>Side to side 1.467</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 199.39 L240.94 199.39 L481.89 199.39" class="st10"/>
+ </g>
+ <g id="shape23-66" v:mID="23" v:groupContext="shape" transform="translate(198.425,-170.079)">
+ <title>Bottom to top 1.468</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape24-69" v:mID="24" v:groupContext="shape" transform="translate(42.5197,-184.252)">
+ <title>Side to side 1.469</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 199.39 L240.94 199.39 L481.89 199.39" class="st10"/>
+ </g>
+ <g id="shape25-72" v:mID="25" v:groupContext="shape" transform="translate(-3.59712E-014,-170.079)">
+ <title>Box.470</title>
+ <desc>VCC</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="21.2598" cy="185.212" width="42.52" height="28.3465"/>
+ <rect x="0" y="171.039" width="42.5197" height="28.3465" class="st9"/>
+ <text x="19.25" y="188.81" class="st2" v:langID="1044"><v:paragraph v:horizAlign="2"/><v:tabList/>V<tspan
+ dy="-0.287em" class="st11" v:baseFontSize="12">CC</tspan></text> </g>
+ <g id="shape26-76" v:mID="26" v:groupContext="shape" transform="translate(269.291,-113.386)">
+ <title>Box.471</title>
+ <desc>I2C DEVICE #2</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="42.5197" cy="171.039" width="85.04" height="56.6929"/>
+ <rect x="0" y="142.692" width="85.0394" height="56.6929" class="st1"/>
+ <text x="9.18" y="167.44" class="st2" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>I2C DEVICE <tspan
+ x="35.85" dy="1.2em" class="st3">#</tspan>2</text> </g>
+ <g id="shape27-80" v:mID="27" v:groupContext="shape" transform="translate(294.094,-70.8661)">
+ <title>Box.472</title>
+ <path d="M0 199.39 L7.09 199.39 L7.09 171.04 L0 171.04 L0 199.39 Z" class="st4"/>
+ </g>
+ <g id="shape28-82" v:mID="28" v:groupContext="shape" transform="translate(322.441,-70.8661)">
+ <title>Box.473</title>
+ <path d="M0 199.39 L7.09 199.39 L7.09 171.04 L0 171.04 L0 199.39 Z" class="st4"/>
+ </g>
+ <g id="shape29-84" v:mID="29" v:groupContext="shape" transform="translate(297.638,-99.2126)">
+ <title>Bottom to top 1.474</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape30-87" v:mID="30" v:groupContext="shape" transform="translate(325.984,-99.2126)">
+ <title>Bottom to top 1.475</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape31-90" v:mID="31" v:groupContext="shape" transform="translate(325.984,-56.6929)">
+ <title>Bottom to top 1.476</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape32-93" v:mID="32" v:groupContext="shape" transform="translate(297.638,-28.3465)">
+ <title>Bottom to top 1.477</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 156.87 L0 178.13 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape33-96" v:mID="33" v:groupContext="shape" transform="translate(301.181,-77.9528)">
+ <title>Sheet.33</title>
+ <desc>RS</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">S</tspan></text> </g>
+ <g id="shape34-100" v:mID="34" v:groupContext="shape" transform="translate(333.071,-77.9528)">
+ <title>Sheet.34</title>
+ <desc>RS</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">S</tspan></text> </g>
+ <g id="shape35-104" v:mID="35" v:groupContext="shape" transform="translate(311.811,-170.079)">
+ <title>Bottom to top 1.480</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape36-107" v:mID="36" v:groupContext="shape" transform="translate(425.197,-113.386)">
+ <title>Box.481</title>
+ <desc>I2C DEVICE #N</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="42.5197" cy="171.039" width="85.04" height="56.6929"/>
+ <rect x="0" y="142.692" width="85.0394" height="56.6929" class="st1"/>
+ <text x="9.18" y="167.44" class="st2" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>I2C DEVICE <tspan
+ x="34.85" dy="1.2em" class="st3">#</tspan>N</text> </g>
+ <g id="shape37-111" v:mID="37" v:groupContext="shape" transform="translate(450,-70.8661)">
+ <title>Box.482</title>
+ <path d="M0 199.39 L7.09 199.39 L7.09 171.04 L0 171.04 L0 199.39 Z" class="st4"/>
+ </g>
+ <g id="shape38-113" v:mID="38" v:groupContext="shape" transform="translate(478.346,-70.8661)">
+ <title>Box.483</title>
+ <path d="M0 199.39 L7.09 199.39 L7.09 171.04 L0 171.04 L0 199.39 Z" class="st4"/>
+ </g>
+ <g id="shape39-115" v:mID="39" v:groupContext="shape" transform="translate(453.543,-99.2126)">
+ <title>Bottom to top 1.484</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape40-118" v:mID="40" v:groupContext="shape" transform="translate(481.89,-99.2126)">
+ <title>Bottom to top 1.485</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape41-121" v:mID="41" v:groupContext="shape" transform="translate(481.89,-56.6929)">
+ <title>Bottom to top 1.486</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape42-124" v:mID="42" v:groupContext="shape" transform="translate(453.543,-28.3465)">
+ <title>Bottom to top 1.487</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 156.87 L0 178.13 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape43-127" v:mID="43" v:groupContext="shape" transform="translate(457.087,-77.9528)">
+ <title>Sheet.43</title>
+ <desc>RS</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">S</tspan></text> </g>
+ <g id="shape44-131" v:mID="44" v:groupContext="shape" transform="translate(488.976,-77.9528)">
+ <title>Sheet.44</title>
+ <desc>RS</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="10.6299" cy="192.299" width="21.26" height="14.1732"/>
+ <rect x="0" y="185.212" width="21.2598" height="14.1732" class="st6"/>
+ <text x="4" y="195.3" class="st7" v:langID="1033"><v:paragraph/><v:tabList/>R<tspan dy="-0.287em" class="st8"
+ v:langID="1044" v:baseFontSize="10">S</tspan></text> </g>
+ <g id="shape45-135" v:mID="45" v:groupContext="shape" transform="translate(467.717,-170.079)">
+ <title>Bottom to top 1.490</title>
+ <v:userDefs>
+ <v:ud v:nameU="TextPos" v:val="VT0(1):26"/>
+ </v:userDefs>
+ <path d="M0 185.21 L0 192.3 L0 199.39" class="st5"/>
+ </g>
+ <g id="shape46-138" v:mID="46" v:groupContext="shape" transform="translate(372.047,-138.189)">
+ <title>Sheet.46</title>
+ <ellipse cx="3.54331" cy="195.842" rx="3.54331" ry="3.54331" class="st12"/>
+ </g>
+ <g id="shape47-140" v:mID="47" v:groupContext="shape" transform="translate(386.22,-138.189)">
+ <title>Sheet.47</title>
+ <ellipse cx="3.54331" cy="195.842" rx="3.54331" ry="3.54331" class="st12"/>
+ </g>
+ <g id="shape48-142" v:mID="48" v:groupContext="shape" transform="translate(400.394,-138.189)">
+ <title>Sheet.48</title>
+ <ellipse cx="3.54331" cy="195.842" rx="3.54331" ry="3.54331" class="st12"/>
+ </g>
+ <g id="shape49-144" v:mID="49" v:groupContext="shape" transform="translate(411.024,0)">
+ <title>Sheet.49</title>
+ <desc>Note: RS is optional</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="56.6929" cy="185.212" width="113.39" height="28.3465"/>
+ <rect x="0" y="171.039" width="113.386" height="28.3465" class="st6"/>
+ <text x="23.34" y="188.21" class="st7" v:langID="1033"><v:paragraph v:horizAlign="2"/><v:tabList/>Note: R<tspan
+ dy="-0.287em" class="st8" v:langID="1044" v:baseFontSize="10">S</tspan><tspan dy="0.186em" class="st3"
+ v:langID="1044"> </tspan><tspan class="st3" v:langID="1044">is optional</tspan></text> </g>
+ </g>
+ </g>
+</svg>
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_read.svg b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_read.svg
new file mode 100644
index 000000000..5be8085d9
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_read.svg
@@ -0,0 +1,1037 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1062.9928"
+ height="39.954796"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="i2c_read.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4"
+ inkscape:cx="431.58384"
+ inkscape:cy="191.3885"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1138"
+ inkscape:window-x="1042"
+ inkscape:window-y="123"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="cm" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-13.760627,-247.09327)">
+ <g
+ id="g3025-8-1"
+ transform="matrix(0.2273934,0,0,0.2273934,337.19144,210.19696)">
+ <g
+ id="g3084-7">
+ <g
+ id="g3137">
+ <rect
+ y="250.80614"
+ x="29.7995"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-2-1"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45-1"
+ y="305.35434"
+ x="68.236969"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="305.35434"
+ x="68.236969"
+ id="tspan2989-5-5"
+ sodipodi:role="line">ACK</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3367"
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.47683)" />
+ <g
+ id="g3651"
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.47683)">
+ <g
+ transform="translate(-15.152288,-49.497478)"
+ id="g3025">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985"
+ width="160.10918"
+ height="84.852814"
+ x="29.7995"
+ y="250.80614" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="45.961941"
+ y="307.37466"
+ id="text2987"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989"
+ x="45.961941"
+ y="307.37466">START</tspan></text>
+ </g>
+ <g
+ transform="translate(0.08928571,0.54971913)"
+ id="g3371">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1"
+ sodipodi:role="line">Bit 0</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3025-0"
+ transform="matrix(0.2273934,0,0,0.2273934,44.171155,210.21446)">
+ <rect
+ y="250.80614"
+ x="29.799496"
+ height="84.852814"
+ width="1126"
+ id="rect2985-9"
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-4"
+ y="307.37466"
+ x="45.961941"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="307.37466"
+ x="45.961941"
+ id="tspan2989-8"
+ sodipodi:role="line">ADDRESS</tspan></text>
+ </g>
+ <g
+ id="g3572"
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.47683)">
+ <g
+ transform="translate(161.20365,0.3799057)"
+ id="g3371-3">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2"
+ sodipodi:role="line">Bit 1</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(322.34682,0.36425801)"
+ id="g3371-3-9">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0"
+ sodipodi:role="line">Bit 2</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(483.53819,0.33959304)"
+ id="g3371-3-2">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-86"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-0">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-2"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-4"
+ sodipodi:role="line">Bit 3</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(644.68136,0.32394304)"
+ id="g3371-3-9-8">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-5">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9"
+ sodipodi:role="line">Bit 4</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(805.87366,0.28165828)"
+ id="g3371-3-0">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-0"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-61">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-3"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-8"
+ sodipodi:role="line">Bit 5</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(967.01682,0.26600828)"
+ id="g3371-3-9-9">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-3"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-4">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-4"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-6"
+ sodipodi:role="line">Bit 6</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(1128.2082,0.24133828)"
+ id="g3371-3-2-0">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-86-6"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-0-6">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-2-1"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-4-8"
+ sodipodi:role="line">Bit 7</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3025-8"
+ transform="matrix(0.2273934,0,0,0.2273934,300.48366,210.19696)">
+ <g
+ id="g3084">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2"
+ width="160.10918"
+ height="84.852814"
+ x="29.7995"
+ y="250.80614" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="57.578697"
+ y="306.3645"
+ id="text2987-45"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5"
+ x="57.578697"
+ y="306.3645">READ</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-8-4"
+ transform="matrix(0.2273934,0,0,0.2273934,303.94836,221.52814)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-9"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-5-6">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-7"
+ x="51.433456"
+ y="170.37161">Bit 8</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-8-4-8"
+ transform="matrix(0.2273934,0,0,0.2273934,340.65614,221.52499)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-9-8"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-5-6-2">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-3-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-7-1"
+ x="51.433456"
+ y="170.37161">Bit 9</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4012"
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.47683)">
+ <g
+ transform="translate(1601.3444,-51.122901)"
+ id="g3137-6">
+ <g
+ transform="translate(-5.2678572,1.5178572)"
+ id="g3184">
+ <rect
+ y="250.80614"
+ x="29.799498"
+ height="84.852814"
+ width="1287"
+ id="rect2985-2-1-1"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45-1-4"
+ y="305.35434"
+ x="68.236969"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="305.35434"
+ x="68.236969"
+ id="tspan2989-5-5-2"
+ sodipodi:role="line">DATA</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3970">
+ <g
+ id="g3371-3-5"
+ transform="translate(1611.2553,0.1918423)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-9"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-8">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-07"
+ x="51.433456"
+ y="170.37161">Bit 10</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-6"
+ transform="translate(1772.3984,0.17619461)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-36"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-1">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-4"
+ x="51.433456"
+ y="170.37161">Bit 11</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-2"
+ transform="translate(1933.5898,0.15152964)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-9">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-7"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-3"
+ x="51.433456"
+ y="170.37161">Bit 12</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-8-7"
+ transform="translate(2094.733,0.13587964)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-2"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-5-60">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-6"
+ x="51.433456"
+ y="170.37161">Bit 13</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-0-5"
+ transform="translate(2255.9253,0.09359488)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-0-7"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-61-5">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-3-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-8-1"
+ x="51.433456"
+ y="170.37161">Bit 14</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-9-2"
+ transform="translate(2417.0684,0.07794488)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-3-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-4-0">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-4-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-6-4"
+ x="51.433456"
+ y="170.37161">Bit 15</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0-6"
+ transform="translate(2578.1601,0.05327488)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6-7">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8-7"
+ x="51.433456"
+ y="170.37161">Bit 16</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0-6-7"
+ transform="translate(2739.1003,0.03811784)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6-0-7"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6-7-7">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1-1-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8-7-3"
+ x="51.433456"
+ y="170.37161">Bit 17</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.4397)"
+ id="g3234">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2-1-16"
+ width="160.10918"
+ height="84.852814"
+ x="2914.0579"
+ y="201.36435" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="2952.4954"
+ y="255.91255"
+ id="text2987-45-1-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5-5-5"
+ x="2952.4954"
+ y="255.91255">ACK</tspan></text>
+ </g>
+ <g
+ id="g3363-7-6-5-6-9"
+ transform="matrix(0.2273934,0,0,0.2273934,670.25138,221.5058)">
+ <g
+ id="g4454">
+ <rect
+ transform="translate(-2899.4747,-0.12740393)"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-9-9"
+ width="160.10918"
+ height="84.852814"
+ x="2914.0376"
+ y="114.94062" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-3-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-7-18"
+ x="51.433456"
+ y="170.37161">Bit 18</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="matrix(0.2273934,0,0,0.2273934,340.5387,221.48936)"
+ id="g4012-2">
+ <g
+ id="g4349">
+ <g
+ id="g3137-6-6"
+ transform="translate(1601.3444,-51.122901)">
+ <g
+ id="g3184-6"
+ transform="translate(-5.2678572,1.5178572)">
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2-1-1-0"
+ width="1287"
+ height="84.852814"
+ x="29.799498"
+ y="250.80614" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="68.236969"
+ y="305.35434"
+ id="text2987-45-1-4-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5-5-2-8"
+ x="68.236969"
+ y="305.35434">DATA</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4307">
+ <g
+ transform="translate(1611.2553,0.1918423)"
+ id="g3371-3-5-1">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-9-2"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-8-5">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-4-0"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-07-9"
+ sodipodi:role="line">Bit 19</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(1772.3984,0.17619461)"
+ id="g3371-3-9-6-4">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-36-7"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-1-8">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-5-3"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-4-5"
+ sodipodi:role="line">Bit 20</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(1933.5898,0.15152964)"
+ id="g3371-3-2-2-1">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-86-0-2"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-0-9-0">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-2-7-1"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-4-3-6"
+ sodipodi:role="line">Bit 21</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(2094.733,0.13587964)"
+ id="g3371-3-9-8-7-4">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6-2-0"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-5-60-6">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0-1-1"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9-6-8"
+ sodipodi:role="line">Bit 22</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(2255.9253,0.09359488)"
+ id="g3371-3-0-5-9">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-0-7-8"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-61-5-4">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-3-4-1"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-8-1-4"
+ sodipodi:role="line">Bit 23</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(2417.0684,0.07794488)"
+ id="g3371-3-9-9-2-3">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-3-0-9"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-4-0-8">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-4-1-8"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-6-4-0"
+ sodipodi:role="line">Bit 24</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(2578.1601,0.05327488)"
+ id="g3371-3-2-0-6-8">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-86-6-0-77"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-0-6-7-8">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-2-1-1-38"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-4-8-7-37"
+ sodipodi:role="line">Bit 25</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(2739.1003,0.03811784)"
+ id="g3371-3-2-0-6-7-1">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-86-6-0-7-0"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-0-6-7-7-7">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-2-1-1-3-3"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-4-8-7-3-4"
+ sodipodi:role="line">Bit 26</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g4561"
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.47683)">
+ <g
+ transform="translate(1449.4207,-0.08294312)"
+ id="g3296">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2-1-16-7"
+ width="160.10918"
+ height="84.852814"
+ x="2914.0579"
+ y="201.36435" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="2941.0669"
+ y="258.05542"
+ id="text2987-45-1-8-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5-5-5-5"
+ x="2941.0669"
+ y="258.05542">NACK</tspan></text>
+ </g>
+ <g
+ transform="translate(4348.9157,0.18342068)"
+ id="g4499">
+ <rect
+ y="114.94062"
+ x="2914.0376"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6-9-9-9"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="translate(-2899.4747,-0.12740393)" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0-3-8-9"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9-7-18-6"
+ sodipodi:role="line">Bit 27</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4571"
+ transform="matrix(0.2273934,0,0,0.2273934,10.929948,221.47683)">
+ <g
+ transform="translate(1610.7689,-0.16325573)"
+ id="g3296-4">
+ <g
+ id="g3328">
+ <rect
+ y="201.36435"
+ x="2914.0579"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-2-1-16-7-3"
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45-1-8-9-1"
+ y="257.04526"
+ x="2945.1074"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="257.04526"
+ x="2945.1074"
+ id="tspan2989-5-5-5-5-2"
+ sodipodi:role="line">STOP</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(4510.1629,0.12740431)"
+ id="g4454-8">
+ <rect
+ transform="translate(-2899.4747,-0.12740393)"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.39766502px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-9-9-3"
+ width="160.10918"
+ height="84.852814"
+ x="2914.0376"
+ y="114.94062" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-3-8-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-7-18-8"
+ x="51.433456"
+ y="170.37161">Bit 28</tspan></text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_write.svg b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_write.svg
new file mode 100644
index 000000000..6f2628100
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/docimg/i2c_write.svg
@@ -0,0 +1,1031 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1062.9977"
+ height="39.199993"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="i2c_write.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.9899495"
+ inkscape:cx="-488.42509"
+ inkscape:cy="-132.2365"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1920"
+ inkscape:window-height="1138"
+ inkscape:window-x="1042"
+ inkscape:window-y="123"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="cm" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-994.63325,-178.88436)">
+ <g
+ id="g3367"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)" />
+ <g
+ id="g3651"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ transform="translate(-15.152288,-49.497478)"
+ id="g3025">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985"
+ width="160.10918"
+ height="84.852814"
+ x="29.7995"
+ y="250.80614" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="45.961941"
+ y="307.37466"
+ id="text2987"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989"
+ x="45.961941"
+ y="307.37466">START</tspan></text>
+ </g>
+ <g
+ transform="translate(0.08928571,0.54971913)"
+ id="g3371">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1"
+ sodipodi:role="line">Bit 0</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3600"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ transform="translate(146.18369,-49.528111)"
+ id="g3025-0">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-9"
+ width="1126"
+ height="84.852814"
+ x="29.799496"
+ y="250.80614" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="45.961941"
+ y="307.37466"
+ id="text2987-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-8"
+ x="45.961941"
+ y="307.37466">ADDRESS</tspan></text>
+ </g>
+ <g
+ id="g3572">
+ <g
+ id="g3371-3"
+ transform="translate(161.20365,0.3799057)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2"
+ x="51.433456"
+ y="170.37161">Bit 1</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9"
+ transform="translate(322.34682,0.36425801)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0"
+ x="51.433456"
+ y="170.37161">Bit 2</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2"
+ transform="translate(483.53819,0.33959304)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4"
+ x="51.433456"
+ y="170.37161">Bit 3</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-8"
+ transform="translate(644.68136,0.32394304)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-5">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9"
+ x="51.433456"
+ y="170.37161">Bit 4</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-0"
+ transform="translate(805.87366,0.28165828)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-61">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-8"
+ x="51.433456"
+ y="170.37161">Bit 5</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-9"
+ transform="translate(967.01682,0.26600828)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-3"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-4">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-6"
+ x="51.433456"
+ y="170.37161">Bit 6</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0"
+ transform="translate(1128.2082,0.24133828)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8"
+ x="51.433456"
+ y="170.37161">Bit 7</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3588"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ transform="translate(1273.3602,-49.605043)"
+ id="g3025-8">
+ <g
+ id="g3084">
+ <rect
+ y="250.80614"
+ x="29.7995"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-2"
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45"
+ y="306.3645"
+ x="45.456867"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="306.3645"
+ x="45.456867"
+ id="tspan2989-5"
+ sodipodi:role="line">WRITE</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(1288.5968,0.22568828)"
+ id="g3371-3-9-8-4">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6-9"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-5-6">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0-3"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9-7"
+ sodipodi:role="line">Bit 8</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3575"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ transform="translate(1434.7887,-49.605043)"
+ id="g3025-8-1">
+ <g
+ id="g3084-7">
+ <g
+ id="g3137">
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2-1"
+ width="160.10918"
+ height="84.852814"
+ x="29.7995"
+ y="250.80614" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="68.236969"
+ y="305.35434"
+ id="text2987-45-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5-5"
+ x="68.236969"
+ y="305.35434">ACK</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ transform="translate(1450.0253,0.21184383)"
+ id="g3371-3-9-8-4-8">
+ <rect
+ y="114.81322"
+ x="14.562887"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6-9-8"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3363-7-6-5-6-2">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0-3-9"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9-7-1"
+ sodipodi:role="line">Bit 9</tspan></text>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g4012"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <rect
+ y="201.2011"
+ x="1625.876"
+ height="84.852814"
+ width="1287"
+ id="rect2985-2-1-1"
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45-1-4"
+ y="255.7493"
+ x="1664.3135"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="255.7493"
+ x="1664.3135"
+ id="tspan2989-5-5-2"
+ sodipodi:role="line">DATA</tspan></text>
+ <g
+ id="g3970">
+ <g
+ id="g3371-3-5"
+ transform="translate(1611.2553,0.1918423)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-9"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-8">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-07"
+ x="51.433456"
+ y="170.37161">Bit 10</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-6"
+ transform="translate(1772.3984,0.17619461)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-36"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-1">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-4"
+ x="51.433456"
+ y="170.37161">Bit 11</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-2"
+ transform="translate(1933.5898,0.15152964)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-9">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-7"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-3"
+ x="51.433456"
+ y="170.37161">Bit 12</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-8-7"
+ transform="translate(2094.733,0.13587964)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-2"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-5-60">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-6"
+ x="51.433456"
+ y="170.37161">Bit 13</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-0-5"
+ transform="translate(2255.9253,0.09359488)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-0-7"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-61-5">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-3-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-8-1"
+ x="51.433456"
+ y="170.37161">Bit 14</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-9-2"
+ transform="translate(2417.0684,0.07794488)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-3-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-4-0">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-4-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-6-4"
+ x="51.433456"
+ y="170.37161">Bit 15</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0-6"
+ transform="translate(2578.1601,0.05327488)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6-7">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8-7"
+ x="51.433456"
+ y="170.37161">Bit 16</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0-6-7"
+ transform="translate(2739.1003,0.03811784)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6-0-7"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6-7-7">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1-1-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8-7-3"
+ x="51.433456"
+ y="170.37161">Bit 17</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3564"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ id="g3559">
+ <rect
+ y="201.2011"
+ x="2914.0579"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-2-1-16"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45-1-8"
+ y="255.7493"
+ x="2952.4954"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="255.7493"
+ x="2952.4954"
+ id="tspan2989-5-5-5"
+ sodipodi:role="line">ACK</tspan></text>
+ </g>
+ <g
+ transform="translate(2899.4747,0.12740393)"
+ id="g3363-7-6-5-6-9">
+ <g
+ id="g4454">
+ <rect
+ y="114.94062"
+ x="2914.0376"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6-9-9"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="translate(-2899.4747,-0.12740393)" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0-3-8"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9-7-18"
+ sodipodi:role="line">Bit 18</tspan></text>
+ </g>
+ </g>
+ </g>
+ <rect
+ y="179.42236"
+ x="1727.759"
+ height="18.926369"
+ width="36.407738"
+ id="rect2985-3-8-8-36-7"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <g
+ id="g3498"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ id="g3361">
+ <rect
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2-1-1-0"
+ width="1287"
+ height="84.852814"
+ x="3075.3848"
+ y="201.2562" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="3113.8223"
+ y="255.8044"
+ id="text2987-45-1-4-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5-5-2-8"
+ x="3113.8223"
+ y="255.8044">DATA</tspan></text>
+ </g>
+ <g
+ id="g3458">
+ <g
+ id="g3371-3-5-1"
+ transform="translate(3060.7641,0.24694231)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-9-2"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-8-5">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-4-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-07-9"
+ x="51.433456"
+ y="170.37161">Bit 19</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3363-7-6-1-8"
+ transform="translate(3221.9072,0.23129462)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-5-3"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-4-5"
+ sodipodi:role="line">Bit 20</tspan></text>
+ </g>
+ <g
+ id="g3371-3-2-2-1"
+ transform="translate(3383.0986,0.20662965)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-0-2"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-9-0">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-7-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-3-6"
+ x="51.433456"
+ y="170.37161">Bit 21</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-8-7-4"
+ transform="translate(3544.2418,0.19097965)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-2-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-5-60-6">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-1-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-6-8"
+ x="51.433456"
+ y="170.37161">Bit 22</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-0-5-9"
+ transform="translate(3705.4341,0.14869489)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-0-7-8"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-61-5-4">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-3-4-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-8-1-4"
+ x="51.433456"
+ y="170.37161">Bit 23</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-9-9-2-3"
+ transform="translate(3866.5772,0.13304489)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-3-0-9"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-6-4-0-8">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-4-1-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-6-4-0"
+ x="51.433456"
+ y="170.37161">Bit 24</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0-6-8"
+ transform="translate(4027.6689,0.10837489)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6-0-77"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6-7-8">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1-1-38"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8-7-37"
+ x="51.433456"
+ y="170.37161">Bit 25</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g3371-3-2-0-6-7-1"
+ transform="translate(4188.6091,0.09321785)">
+ <rect
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-86-6-0-7-0"
+ width="160.10918"
+ height="84.852814"
+ x="14.562887"
+ y="114.81322" />
+ <g
+ id="g3363-7-0-6-7-7-7">
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-2-1-1-3-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-4-8-7-3-4"
+ x="51.433456"
+ y="170.37161">Bit 26</tspan></text>
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g3351"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ id="g3346">
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-2-1-16-7"
+ width="160.10918"
+ height="84.852814"
+ x="4363.4785"
+ y="201.2814" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="4402.6099"
+ y="257.97247"
+ id="text2987-45-1-8-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-5-5-5-5"
+ x="4402.6099"
+ y="257.97247">ACK</tspan></text>
+ </g>
+ <g
+ transform="translate(4348.9157,0.18342068)"
+ id="g4499">
+ <rect
+ y="114.94062"
+ x="2914.0376"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-3-8-8-6-9-9-9"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="translate(-2899.4747,-0.12740393)" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-41-4-5-0-3-8-9"
+ y="170.37161"
+ x="51.433456"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="170.37161"
+ x="51.433456"
+ id="tspan2989-1-2-0-9-7-18-6"
+ sodipodi:role="line">Bit 27</tspan></text>
+ </g>
+ </g>
+ <g
+ id="g4571"
+ transform="matrix(0.22739325,0,0,0.22304957,991.80606,153.76187)">
+ <g
+ transform="translate(1610.7689,-0.16325573)"
+ id="g3296-4">
+ <g
+ id="g3328">
+ <rect
+ y="201.36435"
+ x="2914.0579"
+ height="84.852814"
+ width="160.10918"
+ id="rect2985-2-1-16-7-3"
+ style="fill:#cccccc;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text2987-45-1-8-9-1"
+ y="257.04526"
+ x="2945.1074"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="257.04526"
+ x="2945.1074"
+ id="tspan2989-5-5-5-5-2"
+ sodipodi:role="line">STOP</tspan></text>
+ </g>
+ </g>
+ <g
+ transform="translate(4510.1629,0.12740431)"
+ id="g4454-8">
+ <rect
+ transform="translate(-2899.4747,-0.12740393)"
+ style="fill:#333333;fill-rule:evenodd;stroke:#000000;stroke-width:4.4402833px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2985-3-8-8-6-9-9-3"
+ width="160.10918"
+ height="84.852814"
+ x="2914.0376"
+ y="114.94062" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Sans"
+ x="51.433456"
+ y="170.37161"
+ id="text2987-41-4-5-0-3-8-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2989-1-2-0-9-7-18-8"
+ x="51.433456"
+ y="170.37161">Bit 28</tspan></text>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_common.h b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_common.h
new file mode 100644
index 000000000..de4f0d23f
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_common.h
@@ -0,0 +1,613 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Common Driver
+ *
+ * Copyright (c) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#ifndef I2C_COMMON_H_INCLUDED
+#define I2C_COMMON_H_INCLUDED
+
+#include <compiler.h>
+#include <sercom.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \if (I2C_MASTER_MODE && I2C_SLAVE_MODE)
+ * \defgroup asfdoc_sam0_sercom_i2c_group SAM I2C (SERCOM I2C) Driver
+ * \elseif I2C_MASTER_MODE
+ * \defgroup asfdoc_sam0_sercom_i2c_group SAM I2C Master Mode (SERCOM I2C) Driver
+ * \elseif I2C_SLAVE_MODE
+ * \defgroup asfdoc_sam0_sercom_i2c_group SAM I2C Slave Mode (SERCOM I2C) Driver
+ * \endif
+ *
+ * This driver for Atmel&reg; | SMART ARM&reg;-based microcontrollers provides
+ * an interface for the configuration and management of the device's SERCOM
+ * I<SUP>2</SUP>C module, for the transfer of data via an I<SUP>2</SUP>C bus.
+ * The following driver API modes are covered by this manual:
+ *
+ * \if I2C_MASTER_MODE
+ * - Master Mode Polled APIs
+ * \endif
+ * \if I2C_MASTER_CALLBACK_MODE
+ * - Master Mode Callback APIs
+ * \endif
+ * \if I2C_SLAVE_MODE
+ * - Slave Mode Polled APIs
+ * \endif
+ * \if I2C_SLAVE_CALLBACK_MODE
+ * - Slave Mode Callback APIs
+ * \endif
+ *
+ * The following peripheral is used by this module:
+ * - SERCOM (Serial Communication Interface)
+ *
+ * The following devices can use this module:
+ * - Atmel | SMART SAM D20/D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D09/D10/D11
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM DA1
+ * - Atmel | SMART SAM C20/C21
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_sercom_i2c_prerequisites
+ * - \ref asfdoc_sam0_sercom_i2c_overview
+ * - \ref asfdoc_sam0_sercom_i2c_special_considerations
+ * - \ref asfdoc_sam0_sercom_i2c_extra
+ * - \ref asfdoc_sam0_sercom_i2c_examples
+ * - \ref asfdoc_sam0_sercom_i2c_api_overview
+ *
+ * \section asfdoc_sam0_sercom_i2c_prerequisites Prerequisites
+ * There are no prerequisites.
+ *
+ * \section asfdoc_sam0_sercom_i2c_overview Module Overview
+ * The outline of this section is as follows:
+ * - \ref asfdoc_sam0_sercom_i2c_module_features
+ * - \ref asfdoc_sam0_sercom_i2c_functional_desc
+ * - \ref asfdoc_sam0_sercom_i2c_bus_topology
+ * - \ref asfdoc_sam0_sercom_i2c_transactions
+ * - \ref asfdoc_sam0_sercom_i2c_multi_master
+ * - \ref asfdoc_sam0_sercom_i2c_bus_states
+ * - \ref asfdoc_sam0_sercom_i2c_timeout
+ * - \ref asfdoc_sam0_sercom_i2c_sleep_modes
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_module_features Driver Feature Macro Definition
+ * <table>
+ * <tr>
+ * <th>Driver Feature Macro</th>
+ * <th>Supported devices</th>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_I2C_10_BIT_ADDRESS</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_I2C_SCL_STRETCH_MODE</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_I2C_SCL_EXTEND_TIMEOUT</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * </table>
+ * \note The specific features are only available in the driver when the selected
+ * device supports those features.
+ * \note When using the I2C high-speed mode for off-board communication,
+ * there are various high frequency interference, which can lead to distortion of the signals
+ * and communication failure. When using Xplained Pro boards in order to test I2C high-speed
+ * communication, the following recommendation should be followed:
+ * - Use the SDA-line on PA08 and SCL-line on PA09 for both boards. This will provide stronger
+ * pull-ups on both SDA and SCL.
+ * - The SCL should not be higher than 1.5MHz.
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_functional_desc Functional Description
+ * The I<SUP>2</SUP>C provides a simple two-wire bidirectional bus consisting of a
+ * wired-AND type serial clock line (SCL) and a wired-AND type serial data line
+ * (SDA).
+ *
+ * The I<SUP>2</SUP>C bus provides a simple, but efficient method of interconnecting
+ * multiple master and slave devices. An arbitration mechanism is provided for
+ * resolving bus ownership between masters, as only one master device may own
+ * the bus at any given time. The arbitration mechanism relies on the wired-AND
+ * connections to avoid bus drivers short-circuiting.
+ *
+ * A unique address is assigned to all slave devices connected to the bus. A
+ * device can contain both master and slave logic, and can emulate multiple
+ * slave devices by responding to more than one address.
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_bus_topology Bus Topology
+ * The I<SUP>2</SUP>C bus topology is illustrated in
+ * \ref asfdoc_sam0_sercom_i2c_bus_topology_figure "the figure below". The pull-up
+ * resistors (Rs) will provide a high level on the bus lines when none of the
+ * I<SUP>2</SUP>C devices are driving the bus. These are optional, and can be
+ * replaced with a constant current source.
+ *
+ * \anchor asfdoc_sam0_sercom_i2c_bus_topology_figure
+ * \image html bus_topology.svg "I2C Bus Topology" Width=100%
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_transactions Transactions
+ * The I<SUP>2</SUP>C standard defines three fundamental transaction formats:
+ * - Master Write
+ * - The master transmits data packets to the slave after addressing it
+ * - Master Read
+ * - The slave transmits data packets to the master after being addressed
+ * - Combined Read/Write
+ * - A combined transaction consists of several write and read transactions
+ *
+ * A data transfer starts with the master issuing a \b Start condition on the
+ * bus, followed by the address of the slave together with a bit to indicate
+ * whether the master wants to read from or write to the slave.
+ * The addressed slave must respond to this by sending an \b ACK back to the
+ * master.
+ *
+ * After this, data packets are sent from the master or slave, according to the
+ * read/write bit. Each packet must be acknowledged (ACK) or not
+ * acknowledged (NACK) by the receiver.
+ *
+ * If a slave responds with a NACK, the master must assume that the slave
+ * cannot receive any more data and cancel the write operation.
+ *
+ * The master completes a transaction by issuing a \b Stop condition.
+ *
+ * A master can issue multiple \b Start conditions during a transaction; this
+ * is then called a \b Repeated \b Start condition.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_address_packets Address Packets
+ * The slave address consists of seven bits. The 8<SUP>th</SUP> bit in the transfer
+ * determines the data direction (read or write). An address packet always
+ * succeeds a \b Start or \b Repeated \b Start condition. The 8<SUP>th</SUP> bit is handled
+ * in the driver, and the user will only have to provide the 7-bit address.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_data_packets Data Packets
+ * Data packets are nine bits long, consisting of one 8-bit data byte, and an
+ * acknowledgement bit. Data packets follow either an address packet or another
+ * data packet on the bus.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_trans_examples Transaction Examples
+ * The gray bits in the following examples are sent from master to slave, and
+ * the white bits are sent from slave to master.
+ * Example of a read transaction is shown in
+ * \ref asfdoc_sam0_sercom_i2c_trans_examples_i2c_read "the figure below". Here, the
+ * master first issues a \b Start condition and gets ownership of the bus. An
+ * address packet with the direction flag set to read is then sent and
+ * acknowledged by the slave. Then the slave sends one data packet which is
+ * acknowledged by the master. The slave sends another packet, which is not
+ * acknowledged by the master and indicates that the master will terminate the
+ * transaction. In the end, the transaction is terminated by the master issuing
+ * a \b Stop condition.
+ *
+ * \anchor asfdoc_sam0_sercom_i2c_trans_examples_i2c_read
+ * \image html i2c_read.svg "I2C Packet Read" Width=100%
+ *
+ * Example of a write transaction is shown in
+ * \ref asfdoc_sam0_sercom_i2c_trans_examples_i2c_write "the figure below". Here, the
+ * master first issues a \b Start condition and gets ownership of the bus. An
+ * address packet with the dir flag set to write is then sent and acknowledged
+ * by the slave. Then the master sends two data packets, each acknowledged by
+ * the slave. In the end, the transaction is terminated by the master issuing
+ * a \b Stop condition.
+ *
+ * \anchor asfdoc_sam0_sercom_i2c_trans_examples_i2c_write
+ * \image html i2c_write.svg "I2C Packet Write" Width=100%
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_packet_timeout Packet Timeout
+ * When a master sends an I<SUP>2</SUP>C packet, there is no way of
+ * being sure that a slave will acknowledge the packet. To avoid stalling the
+ * device forever while waiting for an acknowledge, a user selectable timeout
+ * is provided in the \ref i2c_master_config struct which
+ * lets the driver exit a read or write operation after the specified time.
+ * The function will then return the STATUS_ERR_TIMEOUT flag.
+ *
+ * This is also the case for the slave when using the functions postfixed
+ * \c _wait.
+ *
+ * The time before the timeout occurs, will be the same as
+ * for \ref asfdoc_sam0_sercom_i2c_unknown_bus_timeout "unknown bus state" timeout.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_repeated_start Repeated Start
+ * To issue a \b Repeated \b Start, the functions postfixed \c _no_stop must be
+ * used.
+ * These functions will not send a \b Stop condition when the transfer is done,
+ * thus the next transfer will start with a \b Repeated \b Start. To end the
+ * transaction, the functions without the \c _no_stop postfix must be used
+ * for the last read/write.
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_multi_master Multi Master
+ * In a multi master environment, arbitration of the bus is important, as only
+ * one master can own the bus at any point.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_arbitration Arbitration
+ *
+ * \par Clock stretching
+ * The serial clock line is always driven by a master device. However, all
+ * devices connected to the bus are allowed stretch the low period of the clock
+ * to slow down the overall clock frequency or to insert wait states while
+ * processing data.
+ * Both master and slave can randomly stretch the clock, which will force the
+ * other device into a wait-state until the clock line goes high again.
+ *
+ * \par Arbitration on the data line
+ * If two masters start transmitting at the same time, they will both transmit
+ * until one master detects that the other master is pulling the data line low.
+ * When this is detected, the master not pulling the line low, will stop the
+ * transmission and wait until the bus is idle.
+ * As it is the master trying to contact the slave with the lowest address that
+ * will get the bus ownership, this will create an arbitration scheme always
+ * prioritizing the slaves with the lowest address in case of a bus collision.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_clock_sync Clock Synchronization
+ * In situations where more than one master is trying to control the bus clock
+ * line at the same time, a clock synchronization algorithm based on the same
+ * principles used for clock stretching is necessary.
+ *
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_bus_states Bus States
+ * As the I<SUP>2</SUP>C bus is limited to one transaction at the time,
+ * a master that wants to perform a bus transaction must wait until the bus is
+ * free.
+ * Because of this, it is necessary for all masters in a multi-master system to
+ * know the current status of the bus to be able to avoid conflicts and to
+ * ensure data integrity.
+ * \li \b IDLE No activity on the bus (between a \b Stop and a new \b Start
+ * condition)
+ * \li \b OWNER If the master initiates a transaction successfully
+ * \li \b BUSY If another master is driving the bus
+ * \li \b UNKNOWN If the master has recently been enabled or connected to
+ * the bus. Is forced to \b IDLE after given
+ * \ref asfdoc_sam0_sercom_i2c_unknown_bus_timeout "timeout" when
+ * the master module is enabled
+ *
+ * The bus state diagram can be seen in
+ * \ref asfdoc_sam0_sercom_i2c_bus_states_figure "the figure below".
+ * \li S: Start condition
+ * \li P: Stop condition
+ * \li Sr: Repeated start condition
+ * \anchor asfdoc_sam0_sercom_i2c_bus_states_figure
+ * \image html bus_state_diagram.svg "I2C Bus State Diagram" Width=100%
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_timeout Bus Timing
+ * Inactive bus timeout for the master and SDA hold time is configurable in the
+ * drivers.
+ *
+ * \subsubsection asfdoc_sam0_sercom_i2c_unknown_bus_timeout Unknown Bus State Timeout
+ * When a master is enabled or connected to the bus, the bus state will be
+ * unknown until either a given timeout or a stop command has occurred. The
+ * timeout is configurable in the \ref i2c_master_config struct.
+ * The timeout time will depend on toolchain and optimization level used, as
+ * the timeout is a loop incrementing a value until it reaches the specified
+ * timeout value.
+ *
+ * \subsubsection sda_hold SDA Hold Timeout
+ * When using the I<SUP>2</SUP>C in slave mode, it will be important to
+ * set a SDA hold time which assures that the master will be able to pick up
+ * the bit sent from the slave. The SDA hold time makes sure that this is the
+ * case by holding the data line low for a given period after the negative edge
+ * on the clock.
+ *
+ * The SDA hold time is also available for the master driver, but is not a
+ * necessity.
+ *
+ * \subsection asfdoc_sam0_sercom_i2c_sleep_modes Operation in Sleep Modes
+ * The I<SUP>2</SUP>C module can operate in all sleep modes by setting
+ * the run_in_standby Boolean in the \ref i2c_master_config or
+ * \ref i2c_slave_config struct.
+ * The operation in slave and master mode is shown in
+ * \ref asfdoc_sam0_sercom_i2c_sleep_modes_table "the table below".
+ *
+ * \anchor asfdoc_sam0_sercom_i2c_sleep_modes_table
+ * <table>
+ * <caption>I2C Standby Operations</caption>
+ * <tr>
+ * <th>Run in standby</th>
+ * <th>Slave</th>
+ * <th>Master</th>
+ * </tr>
+ * <tr>
+ * <td>false</td>
+ * <td>Disabled, all reception is dropped</td>
+ * <td>Generic Clock (GCLK) disabled when master is idle</td>
+ * </tr>
+ * <tr>
+ * <td>true</td>
+ * <td>Wake on address match when enabled</td>
+ * <td>GCLK enabled while in sleep modes</td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \section asfdoc_sam0_sercom_i2c_special_considerations Special Considerations
+ *
+ * \if (I2C_MASTER_CALLBACK_MODE || I2C_SLAVE_CALLBACK_MODE)
+ * \subsection asfdoc_sam0_sercom_i2c_common_interrupt Interrupt-driven Operation
+ * While an interrupt-driven operation is in progress, subsequent calls to a
+ * write or read operation will return the STATUS_BUSY flag, indicating that
+ * only one operation is allowed at any given time.
+ *
+ * To check if another transmission can be initiated, the user can either call
+ * another transfer operation, or use the
+ * \ref i2c_master_get_job_status/\ref i2c_slave_get_job_status functions
+ * depending on mode.
+ *
+ * If the user would like to get callback from operations while using the
+ * interrupt-driven driver, the callback must be registered and then enabled
+ * using the "register_callback" and "enable_callback" functions.
+ * \else
+ * There are no special considerations for this driver for the APIs listed in
+ * this document.
+ * \endif
+ *
+ * \section asfdoc_sam0_sercom_i2c_extra Extra Information
+ * For extra information, see \ref asfdoc_sam0_sercom_i2c_extra_info_page.
+ * This includes:
+ * - \ref asfdoc_sam0_sercom_i2c_acronyms
+ * - \ref asfdoc_sam0_sercom_i2c_extra_dependencies
+ * - \ref asfdoc_sam0_sercom_i2c_extra_errata
+ * - \ref asfdoc_sam0_sercom_i2c_extra_history
+ *
+ * \section asfdoc_sam0_sercom_i2c_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_sercom_i2c_exqsg.
+ *
+ * \section asfdoc_sam0_sercom_i2c_api_overview API Overview
+ * @{
+ */
+
+/**
+ * \name Driver Feature Definition
+ * Define SERCOM I<SUP>2</SUP>C driver features set according to different device family.
+ *
+ * @{
+ */
+#if (SAMD21) || (SAMR21) || (SAMD10) || (SAMD11) || (SAML21) || (SAMDA1) || \
+ (SAML22) || (SAMC20) || (SAMC21) || (SAMD09) || (SAMR30) || defined(__DOXYGEN__)
+/** Fast mode plus and high speed support. */
+# define FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+/** 10-bit address support */
+# define FEATURE_I2C_10_BIT_ADDRESS
+/** SCL stretch mode support */
+# define FEATURE_I2C_SCL_STRETCH_MODE
+/** SCL extend timeout support */
+# define FEATURE_I2C_SCL_EXTEND_TIMEOUT
+# define FEATURE_I2C_DMA_SUPPORT
+#endif
+/*@}*/
+
+/** \brief Transfer direction
+ *
+ * For master: transfer direction or setting direction bit in address.
+ * For slave: direction of request from master.
+ */
+enum i2c_transfer_direction {
+ /** Master write operation is in progress */
+ I2C_TRANSFER_WRITE = 0,
+ /** Master read operation is in progress */
+ I2C_TRANSFER_READ = 1,
+};
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * \page asfdoc_sam0_sercom_i2c_extra_info_page Extra Information for SERCOM I2C Driver
+ *
+ * \section asfdoc_sam0_sercom_i2c_acronyms Acronyms
+ * \ref asfdoc_sam0_sercom_i2c_acronyms_table "Below" is a table listing the acronyms
+ * used in this module, along with their intended meanings.
+ *
+ * \anchor asfdoc_sam0_sercom_i2c_acronyms_table
+ * <table>
+ * <caption>Acronyms</caption>
+ * <tr>
+ * <th>Acronym</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td>SDA</td>
+ * <td>Serial Data Line</td>
+ * </tr>
+ * <tr>
+ * <td>SCL</td>
+ * <td>Serial Clock Line</td>
+ * </tr>
+ * <tr>
+ * <td>SERCOM</td>
+ * <td>Serial Communication Interface</td>
+ * </tr>
+ * <tr>
+ * <td>DMA</td>
+ * <td>Direct Memory Access</td>
+ * </tr>
+ * </table>
+ *
+ * \section asfdoc_sam0_sercom_i2c_extra_dependencies Dependencies
+ * The I<SUP>2</SUP>C driver has the following dependencies:
+ * \li \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
+ *
+ *
+ * \section asfdoc_sam0_sercom_i2c_extra_errata Errata
+ * There are no errata related to this driver.
+ *
+ * \section asfdoc_sam0_sercom_i2c_extra_history Module History
+ * \ref asfdoc_sam0_sercom_i2c_extra_history_table "Below" is an overview of the
+ * module history, detailing enhancements and fixes made to the module since
+ * its first release. The current version of this corresponds to the newest
+ * version listed in
+ * \ref asfdoc_sam0_sercom_i2c_extra_history_table "the table below".
+ *
+ * \anchor asfdoc_sam0_sercom_i2c_extra_history_table
+ * <table>
+ * <caption>Module History</caption>
+ * <tr>
+ * <th>Changelog</th>
+ * </tr>
+ * <tr>
+ * <td>
+ * \li Added 10-bit addressing and high speed support in SAM D21
+ * \li Separate structure i2c_packet into i2c_master_packet and i2c_slave packet
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>
+ * \li Added support for SCL stretch and extended timeout hardware features in SAM D21
+ * \li Added fast mode plus support in SAM D21
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>Fixed incorrect logical mask for determining if a bus error has
+ * occurred in I<SUP>2</SUP>C Slave mode
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * </table>
+ */
+
+/**
+ * \page asfdoc_sam0_sercom_i2c_exqsg Examples for SERCOM I2C Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_sercom_i2c_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that a QSG can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * \if I2C_MASTER_MODE
+ * - \subpage asfdoc_sam0_sercom_i2c_master_basic_use_case "Quick Start Guide for the I2C Master module - Basic Use Case"
+ * \endif
+ * \if I2C_MASTER_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_sercom_i2c_master_callback_use_case "Quick Start Guide for the I2C Master module - Callback Use Case"
+ * - \subpage asfdoc_sam0_sercom_i2c_master_dma_use_case "Quick Start Guide for the I2C Master module - DMA Use Case"
+ * \endif
+ * \if I2C_SLAVE_MODE
+ * - \subpage asfdoc_sam0_sercom_i2c_slave_basic_use_case "Quick Start Guide for the I2C Slave module - Basic Use Case"
+ * \endif
+ * \if I2C_SLAVE_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_sercom_i2c_slave_callback_use_case "Quick Start Guide for the I2C Slave module - Callback Use Case"
+ * - \subpage asfdoc_sam0_sercom_i2c_slave_dma_use_case "Quick Start Guide for the I2C Slave module - DMA Use Case"
+ * \endif
+ *
+ * \page asfdoc_sam0_sercom_i2c_document_revision_history Document Revision History
+ *
+ * \if (I2C_MASTER_MODE || I2C_MASTER_CALLBACK_MODE)
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</th>
+ * <th>Date</th>
+ * <th>Comments</th>
+ * </tr>
+ * <tr>
+ * <td>42117E</td>
+ * <td>12/2015</td>
+ * <td>Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21</td>
+ * </tr>
+ * <tr>
+ * <td>42117D</td>
+ * <td>12/2014</td>
+ * <td>Added support for 10-bit addressing and high speed in SAM D21.
+ * Added support for SAM R21 and SAM D10/D11.</td>
+ * </tr>
+ * <tr>
+ * <td>42117C</td>
+ * <td>01/2014</td>
+ * <td>Added support for SAM D21</td>
+ * </tr>
+ * <tr>
+ * <td>42117B</td>
+ * <td>06/2013</td>
+ * <td>Corrected documentation typos. Updated I<SUP>2</SUP>C Bus State Diagram.</td>
+ * </tr>
+ * <tr>
+ * <td>42117A</td>
+ * <td>06/2013</td>
+ * <td>Initial release</td>
+ * </tr>
+ * </table>
+ * \else
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</th>
+ * <th>Date</th>
+ * <th>Comments</th>
+ * </tr>
+ * <tr>
+ * <td>42116E</td>
+ * <td>12/2015</td>
+ * <td>Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21</td>
+ * </tr>
+ * <tr>
+ * <td>42116D</td>
+ * <td>12/2014</td>
+ * <td>Added support for 10-bit addressing and high speed in SAM D21.
+ * Added support for SAM R21 and SAM D10/D11.</td>
+ * </tr>
+ * <tr>
+ * <td>42116C</td>
+ * <td>01/2014</td>
+ * <td>Added support for SAM D21</td>
+ * </tr>
+ * <tr>
+ * <td>42116B</td>
+ * <td>06/2013</td>
+ * <td>Corrected documentation typos. Updated I<SUP>2</SUP>C Bus State Diagram.</td>
+ * </tr>
+ * <tr>
+ * <td>42116A</td>
+ * <td>06/2013</td>
+ * <td>Initial release</td>
+ * </tr>
+ * </table>
+ *\endif
+ */
+
+#endif /* I2C_COMMON_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master.h b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master.h
new file mode 100644
index 000000000..79c2effe8
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master.h
@@ -0,0 +1,629 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Master Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef I2C_MASTER_H_INCLUDED
+#define I2C_MASTER_H_INCLUDED
+
+#include "i2c_common.h"
+#include <sercom.h>
+#include <pinmux.h>
+
+#if I2C_MASTER_CALLBACK_MODE == true
+# include <sercom_interrupt.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef PINMUX_DEFAULT
+# define PINMUX_DEFAULT 0
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_i2c_group
+ *
+ * @{
+ */
+
+/**
+ * \brief I<SUP>2</SUP>C master packet for read/write
+ *
+ * Structure to be used when transferring I<SUP>2</SUP>C master packets.
+ */
+struct i2c_master_packet {
+ /** Address to slave device */
+ uint16_t address;
+ /** Length of data array */
+ uint16_t data_length;
+ /** Data array containing all data to be transferred */
+ uint8_t *data;
+ /** Use 10-bit addressing. Set to false if the feature is not supported by the device */
+ bool ten_bit_address;
+ /** Use high speed transfer. Set to false if the feature is not supported by the device */
+ bool high_speed;
+ /** High speed mode master code (0000 1XXX), valid when high_speed is true */
+ uint8_t hs_master_code;
+};
+
+/** \brief Interrupt flags
+ *
+ * Flags used when reading or setting interrupt flags.
+ */
+enum i2c_master_interrupt_flag {
+ /** Interrupt flag used for write */
+ I2C_MASTER_INTERRUPT_WRITE = 0,
+ /** Interrupt flag used for read */
+ I2C_MASTER_INTERRUPT_READ = 1,
+};
+
+/**
+ * \brief Values for hold time after start bit.
+ *
+ * Values for the possible I<SUP>2</SUP>C master mode SDA internal hold times after start
+ * bit has been sent.
+ */
+enum i2c_master_start_hold_time {
+ /** Internal SDA hold time disabled */
+ I2C_MASTER_START_HOLD_TIME_DISABLED = SERCOM_I2CM_CTRLA_SDAHOLD(0),
+ /** Internal SDA hold time 50ns - 100ns */
+ I2C_MASTER_START_HOLD_TIME_50NS_100NS = SERCOM_I2CM_CTRLA_SDAHOLD(1),
+ /** Internal SDA hold time 300ns - 600ns */
+ I2C_MASTER_START_HOLD_TIME_300NS_600NS = SERCOM_I2CM_CTRLA_SDAHOLD(2),
+ /** Internal SDA hold time 400ns - 800ns */
+ I2C_MASTER_START_HOLD_TIME_400NS_800NS = SERCOM_I2CM_CTRLA_SDAHOLD(3),
+};
+
+/**
+ * \brief Values for inactive bus time-out.
+ *
+ * If the inactive bus time-out is enabled and the bus is inactive for
+ * longer than the time-out setting, the bus state logic will be set to idle.
+ */
+enum i2c_master_inactive_timeout {
+ /** Inactive bus time-out disabled */
+ I2C_MASTER_INACTIVE_TIMEOUT_DISABLED = SERCOM_I2CM_CTRLA_INACTOUT(0),
+ /** Inactive bus time-out 5-6 SCL cycle time-out */
+ I2C_MASTER_INACTIVE_TIMEOUT_55US = SERCOM_I2CM_CTRLA_INACTOUT(1),
+ /** Inactive bus time-out 10-11 SCL cycle time-out */
+ I2C_MASTER_INACTIVE_TIMEOUT_105US = SERCOM_I2CM_CTRLA_INACTOUT(2),
+ /** Inactive bus time-out 20-21 SCL cycle time-out */
+ I2C_MASTER_INACTIVE_TIMEOUT_205US = SERCOM_I2CM_CTRLA_INACTOUT(3),
+};
+
+/**
+ * \brief I<SUP>2</SUP>C frequencies
+ *
+ * Values for I<SUP>2</SUP>C speeds supported by the module. The driver
+ * will also support setting any other value, in which case set
+ * the value in the \ref i2c_master_config at desired value divided by 1000.
+ *
+ * Example: If 10KHz operation is required, give baud_rate in the configuration
+ * structure the value 10.
+ */
+enum i2c_master_baud_rate {
+ /** Baud rate at 100KHz (Standard-mode) */
+ I2C_MASTER_BAUD_RATE_100KHZ = 100,
+ /** Baud rate at 400KHz (Fast-mode) */
+ I2C_MASTER_BAUD_RATE_400KHZ = 400,
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+ /** Baud rate at 1MHz (Fast-mode Plus) */
+ I2C_MASTER_BAUD_RATE_1000KHZ = 1000,
+ /** Baud rate at 3.4MHz (High-speed mode) */
+ I2C_MASTER_BAUD_RATE_3400KHZ = 3400,
+#endif
+};
+
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+/**
+ * \brief Enum for the transfer speed
+ *
+ * Enum for the transfer speed.
+ */
+enum i2c_master_transfer_speed {
+ /** Standard-mode (Sm) up to 100KHz and Fast-mode (Fm) up to 400KHz */
+ I2C_MASTER_SPEED_STANDARD_AND_FAST = SERCOM_I2CM_CTRLA_SPEED(0),
+ /** Fast-mode Plus (Fm+) up to 1MHz */
+ I2C_MASTER_SPEED_FAST_MODE_PLUS = SERCOM_I2CM_CTRLA_SPEED(1),
+ /** High-speed mode (Hs-mode) up to 3.4MHz */
+ I2C_MASTER_SPEED_HIGH_SPEED = SERCOM_I2CM_CTRLA_SPEED(2),
+};
+#endif
+
+#if I2C_MASTER_CALLBACK_MODE == true
+/**
+ * \brief Callback types
+ *
+ * The available callback types for the I<SUP>2</SUP>C master module.
+ */
+enum i2c_master_callback {
+ /** Callback for packet write complete */
+ I2C_MASTER_CALLBACK_WRITE_COMPLETE = 0,
+ /** Callback for packet read complete */
+ I2C_MASTER_CALLBACK_READ_COMPLETE = 1,
+ /** Callback for error */
+ I2C_MASTER_CALLBACK_ERROR = 2,
+# if !defined(__DOXYGEN__)
+ /** Total number of callbacks */
+ _I2C_MASTER_CALLBACK_N = 3,
+# endif
+};
+
+# if !defined(__DOXYGEN__)
+/* Prototype for software module */
+struct i2c_master_module;
+
+typedef void (*i2c_master_callback_t)(
+ struct i2c_master_module *const module);
+# endif
+#endif
+
+/**
+ * \brief SERCOM I<SUP>2</SUP>C Master driver software device instance structure.
+ *
+ * SERCOM I<SUP>2</SUP>C Master driver software instance structure, used to
+ * retain software state information of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved for module-internal use only.
+ */
+struct i2c_master_module {
+#if !defined(__DOXYGEN__)
+ /** Hardware instance initialized for the struct */
+ Sercom *hw;
+ /** Module lock */
+ volatile bool locked;
+ /** Unknown bus state timeout */
+ uint16_t unknown_bus_state_timeout;
+ /** Buffer write timeout value */
+ uint16_t buffer_timeout;
+ /** If true, stop condition will be sent after a read/write */
+ bool send_stop;
+ /** If true, nack signal will be sent after a read/write */
+ bool send_nack;
+# if I2C_MASTER_CALLBACK_MODE == true
+ /** Pointers to callback functions */
+ volatile i2c_master_callback_t callbacks[_I2C_MASTER_CALLBACK_N];
+ /** Mask for registered callbacks */
+ volatile uint8_t registered_callback;
+ /** Mask for enabled callbacks */
+ volatile uint8_t enabled_callback;
+ /** The total number of bytes to transfer */
+ volatile uint16_t buffer_length;
+ /**
+ * Counter used for bytes left to send in write and to count number of
+ * obtained bytes in read
+ */
+ volatile uint16_t buffer_remaining;
+ /** Data buffer for packet write and read */
+ volatile uint8_t *buffer;
+ /** Save direction of async request. 1 = read, 0 = write */
+ volatile enum i2c_transfer_direction transfer_direction;
+ /** Status for status read back in error callback */
+ volatile enum status_code status;
+# endif
+#endif
+};
+
+/**
+ * \brief Configuration structure for the I<SUP>2</SUP>C Master device
+ *
+ * This is the configuration structure for the I<SUP>2</SUP>C Master device. It
+ * is used as an argument for \ref i2c_master_init to provide the desired
+ * configurations for the module. The structure should be initialized using the
+ * \ref i2c_master_get_config_defaults.
+ */
+struct i2c_master_config {
+ /** Baud rate (in KHz) for I<SUP>2</SUP>C operations in
+ * standard-mode, Fast-mode, and Fast-mode Plus Transfers,
+ * \ref i2c_master_baud_rate */
+ uint32_t baud_rate;
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+ /** Baud rate (in KHz) for I<SUP>2</SUP>C operations in
+ * High-speed mode, \ref i2c_master_baud_rate */
+ uint32_t baud_rate_high_speed;
+ /** Transfer speed mode */
+ enum i2c_master_transfer_speed transfer_speed;
+#endif
+ /** GCLK generator to use as clock source */
+ enum gclk_generator generator_source;
+ /** Bus hold time after start signal on data line */
+ enum i2c_master_start_hold_time start_hold_time;
+ /** Unknown bus state \ref asfdoc_sam0_sercom_i2c_unknown_bus_timeout "timeout" */
+ uint16_t unknown_bus_state_timeout;
+ /** Timeout for packet write to wait for slave */
+ uint16_t buffer_timeout;
+ /** Set to keep module active in sleep modes */
+ bool run_in_standby;
+ /** PAD0 (SDA) pinmux */
+ uint32_t pinmux_pad0;
+ /** PAD1 (SCL) pinmux */
+ uint32_t pinmux_pad1;
+ /** Set to enable SCL low time-out */
+ bool scl_low_timeout;
+ /** Inactive bus time out */
+ enum i2c_master_inactive_timeout inactive_timeout;
+#ifdef FEATURE_I2C_SCL_STRETCH_MODE
+ /** Set to enable SCL stretch only after ACK bit (required for high speed) */
+ bool scl_stretch_only_after_ack_bit;
+#endif
+#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT
+ /** Set to enable slave SCL low extend time-out */
+ bool slave_scl_low_extend_timeout;
+ /** Set to enable maser SCL low extend time-out */
+ bool master_scl_low_extend_timeout;
+#endif
+ /** Get more accurate BAUD, considering rise time(required for standard-mode and Fast-mode) */
+ uint16_t sda_scl_rise_time_ns;
+};
+
+/**
+ * \name Lock/Unlock
+ * @{
+ */
+
+/**
+ * \brief Attempt to get lock on driver instance
+ *
+ * This function checks the instance's lock, which indicates whether or not it
+ * is currently in use, and sets the lock if it was not already set.
+ *
+ * The purpose of this is to enable exclusive access to driver instances, so
+ * that, e.g., transactions by different services will not interfere with each
+ * other.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline enum status_code i2c_master_lock(
+ struct i2c_master_module *const module)
+{
+ enum status_code status;
+
+ system_interrupt_enter_critical_section();
+
+ if (module->locked) {
+ status = STATUS_BUSY;
+ } else {
+ module->locked = true;
+ status = STATUS_OK;
+ }
+
+ system_interrupt_leave_critical_section();
+
+ return status;
+}
+
+/**
+ * \brief Unlock driver instance
+ *
+ * This function clears the instance lock, indicating that it is available for
+ * use.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline void i2c_master_unlock(struct i2c_master_module *const module)
+{
+ module->locked = false;
+}
+
+/** @} */
+
+/**
+ * \name Configuration and Initialization
+ * @{
+ */
+
+/**
+ * \brief Returns the synchronization status of the module
+ *
+ * Returns the synchronization status of the module.
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Status of the synchronization.
+ * \retval true Module is busy synchronizing
+ * \retval false Module is not synchronizing
+ */
+static inline bool i2c_master_is_syncing (
+ const struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_hw = &(module->hw->I2CM);
+
+#if defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1)
+ return (i2c_hw->STATUS.reg & SERCOM_I2CM_STATUS_SYNCBUSY);
+#elif defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2)
+ return (i2c_hw->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK);
+#else
+# error Unknown SERCOM SYNCBUSY scheme!
+#endif
+}
+
+#if !defined(__DOXYGEN__)
+/**
+ * \internal
+ * Wait for hardware module to sync
+ *
+ * \param[in] module Pointer to software module structure
+ */
+static void _i2c_master_wait_for_sync(
+ const struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+
+ while (i2c_master_is_syncing(module)) {
+ /* Wait for I2C module to sync. */
+ }
+}
+#endif
+
+/**
+ * \brief Gets the I<SUP>2</SUP>C master default configurations
+ *
+ * Use to initialize the configuration structure to known default values.
+ *
+ * The default configuration is as follows:
+ * - Baudrate 100KHz
+ * - GCLK generator 0
+ * - Do not run in standby
+ * - Start bit hold time 300ns - 600ns
+ * - Buffer timeout = 65535
+ * - Unknown bus status timeout = 65535
+ * - Do not run in standby
+ * - PINMUX_DEFAULT for SERCOM pads
+ *
+ * Those default configuration only available if the device supports it:
+ * - High speed baudrate 3.4MHz
+ * - Standard-mode and Fast-mode transfer speed
+ * - SCL stretch disabled
+ * - Slave SCL low extend time-out disabled
+ * - Master SCL low extend time-out disabled
+ *
+ * \param[out] config Pointer to configuration structure to be initiated
+ */
+static inline void i2c_master_get_config_defaults(
+ struct i2c_master_config *const config)
+{
+ /*Sanity check argument */
+ Assert(config);
+ config->baud_rate = I2C_MASTER_BAUD_RATE_100KHZ;
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+ config->baud_rate_high_speed = I2C_MASTER_BAUD_RATE_3400KHZ;
+ config->transfer_speed = I2C_MASTER_SPEED_STANDARD_AND_FAST;
+#endif
+ config->generator_source = GCLK_GENERATOR_0;
+ config->run_in_standby = false;
+ config->start_hold_time = I2C_MASTER_START_HOLD_TIME_300NS_600NS;
+ config->buffer_timeout = 65535;
+ config->unknown_bus_state_timeout = 65535;
+ config->pinmux_pad0 = PINMUX_DEFAULT;
+ config->pinmux_pad1 = PINMUX_DEFAULT;
+ config->scl_low_timeout = false;
+ config->inactive_timeout = I2C_MASTER_INACTIVE_TIMEOUT_DISABLED;
+#ifdef FEATURE_I2C_SCL_STRETCH_MODE
+ config->scl_stretch_only_after_ack_bit = false;
+#endif
+#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT
+ config->slave_scl_low_extend_timeout = false;
+ config->master_scl_low_extend_timeout = false;
+#endif
+ /* The typical value is 215ns */
+ config->sda_scl_rise_time_ns = 215;
+}
+
+enum status_code i2c_master_init(
+ struct i2c_master_module *const module,
+ Sercom *const hw,
+ const struct i2c_master_config *const config);
+
+/**
+ * \brief Enables the I<SUP>2</SUP>C module
+ *
+ * Enables the requested I<SUP>2</SUP>C module and set the bus state to IDLE
+ * after the specified \ref asfdoc_sam0_sercom_i2c_timeout "timeout" period if no
+ * stop bit is detected.
+ *
+ * \param[in] module Pointer to the software module struct
+ */
+static inline void i2c_master_enable(
+ const struct i2c_master_module *const module)
+{
+ /* Sanity check of arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Timeout counter used to force bus state */
+ uint32_t timeout_counter = 0;
+
+ /* Wait for module to sync */
+ _i2c_master_wait_for_sync(module);
+
+ /* Enable module */
+ i2c_module->CTRLA.reg |= SERCOM_I2CM_CTRLA_ENABLE;
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Enable module interrupts */
+ system_interrupt_enable(_sercom_get_interrupt_vector(module->hw));
+#endif
+ /* Start timeout if bus state is unknown */
+ while (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(1))) {
+ timeout_counter++;
+ if(timeout_counter >= (module->unknown_bus_state_timeout)) {
+ /* Timeout, force bus state to idle */
+ i2c_module->STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1);
+ /* Workaround #1 */
+ return;
+ }
+ }
+}
+
+/**
+ * \brief Disable the I<SUP>2</SUP>C module
+ *
+ * Disables the requested I<SUP>2</SUP>C module.
+ *
+ * \param[in] module Pointer to the software module struct
+ */
+static inline void i2c_master_disable(
+ const struct i2c_master_module *const module)
+{
+ /* Sanity check of arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Disable module interrupts */
+ system_interrupt_disable(_sercom_get_interrupt_vector(module->hw));
+#endif
+
+ /* Wait for module to sync */
+ _i2c_master_wait_for_sync(module);
+
+ /* Disbale interrupt */
+ i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MASK;
+ /* Clear interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_MASK;
+
+ /* Disable module */
+ i2c_module->CTRLA.reg &= ~SERCOM_I2CM_CTRLA_ENABLE;
+
+}
+
+void i2c_master_reset(struct i2c_master_module *const module);
+
+/** @} */
+
+/**
+* \name Read and Write
+* @{
+*/
+
+enum status_code i2c_master_read_packet_wait(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_read_packet_wait_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_packet_wait(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_packet_wait_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+void i2c_master_send_stop(struct i2c_master_module *const module);
+
+void i2c_master_send_nack(struct i2c_master_module *const module);
+
+enum status_code i2c_master_read_byte(
+ struct i2c_master_module *const module,
+ uint8_t *byte);
+
+enum status_code i2c_master_write_byte(
+ struct i2c_master_module *const module,
+ uint8_t byte);
+
+enum status_code i2c_master_read_packet_wait_no_nack(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+/** @} */
+
+#ifdef FEATURE_I2C_DMA_SUPPORT
+/**
+* \name SERCOM I2C Master with DMA Interfaces
+* @{
+*/
+
+/**
+ * \brief Set I<SUP>2</SUP>C for DMA transfer with slave address and transfer size.
+ *
+ * This function will set the slave address, transfer size and enable the auto transfer
+ * mode for DMA.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ * \param[in] addr I<SUP>2</SUP>C slave address
+ * \param[in] length I<SUP>2</SUP>C transfer length with DMA
+ * \param[in] direction I<SUP>2</SUP>C transfer direction
+ *
+ */
+static inline void i2c_master_dma_set_transfer(struct i2c_master_module *const module,
+ uint16_t addr, uint8_t length, enum i2c_transfer_direction direction)
+{
+ module->hw->I2CM.ADDR.reg =
+ SERCOM_I2CM_ADDR_ADDR(addr<<1) |
+ SERCOM_I2CM_ADDR_LENEN |
+ SERCOM_I2CM_ADDR_LEN(length) |
+ direction;
+}
+
+/** @} */
+#endif
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I2C_MASTER_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master_interrupt.h b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master_interrupt.h
new file mode 100644
index 000000000..249525d3c
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_master_interrupt.h
@@ -0,0 +1,214 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Master Interrupt Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef I2C_MASTER_INTERRUPT_H_INCLUDED
+#define I2C_MASTER_INTERRUPT_H_INCLUDED
+
+#include "i2c_master.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_i2c_group
+ * @{
+ *
+ */
+
+/**
+ * \name Callbacks
+ * @{
+ */
+#if !defined(__DOXYGEN__)
+void _i2c_master_interrupt_handler(
+ uint8_t instance);
+#endif
+
+void i2c_master_register_callback(
+ struct i2c_master_module *const module,
+ i2c_master_callback_t callback,
+ enum i2c_master_callback callback_type);
+
+void i2c_master_unregister_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type);
+
+/**
+ * \brief Enables callback
+ *
+ * Enables the callback specified by the callback_type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to enable
+ */
+static inline void i2c_master_enable_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Mark callback as enabled */
+ module->enabled_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Disables callback
+ *
+ * Disables the callback specified by the callback_type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to disable
+ */
+static inline void i2c_master_disable_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Mark callback as disabled */
+ module->enabled_callback &= ~(1 << callback_type);
+}
+
+/** @} */
+
+/**
+ * \name Read and Write, Interrupt-driven
+ * @{
+ */
+
+enum status_code i2c_master_read_bytes(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_read_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_read_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_read_packet_job_no_nack(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_bytes(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+enum status_code i2c_master_write_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet);
+
+/**
+ * \brief Cancel any currently ongoing operation
+ *
+ * Terminates the running transfer operation.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static inline void i2c_master_cancel_job(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Set buffer to 0 */
+ module->buffer_remaining = 0;
+ /* Update status */
+ module->status = STATUS_ABORTED;
+}
+
+/**
+ * \brief Get status from ongoing job
+ *
+ * Will return the status of a transfer operation.
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Last status code from transfer operation.
+ * \retval STATUS_OK No error has occurred
+ * \retval STATUS_BUSY If transfer is in progress
+ * \retval STATUS_BUSY If master module is busy
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ * \retval STATUS_ERR_TIMEOUT If timeout occurred
+ * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent
+ * data, indicating that slave does not
+ * want more data and was not able to read
+ */
+static inline enum status_code i2c_master_get_job_status(
+ struct i2c_master_module *const module)
+{
+ /* Check sanity */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Return current status code */
+ return module->status;
+}
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I2C_MASTER_INTERRUPT_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c
new file mode 100644
index 000000000..4e37b4f09
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master.c
@@ -0,0 +1,1050 @@
+/**
+ * \file
+ *
+ * \brief SAM I2C Master Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_master.h"
+
+#if I2C_MASTER_CALLBACK_MODE == true
+# include "i2c_master_interrupt.h"
+#endif
+
+/* Forward declaration */
+enum status_code _i2c_master_wait_for_bus(
+ struct i2c_master_module *const module);
+
+enum status_code _i2c_master_address_response(
+ struct i2c_master_module *const module);
+
+enum status_code _i2c_master_send_hs_master_code(
+ struct i2c_master_module *const module,
+ uint8_t hs_master_code);
+
+#if !defined(__DOXYGEN__)
+
+/**
+ * \internal Sets configurations to module
+ *
+ * \param[out] module Pointer to software module structure
+ * \param[in] config Configuration structure with configurations to set
+ *
+ * \return Status of setting configuration.
+ * \retval STATUS_OK If module was configured correctly
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible
+ * with set GCLK frequency
+ */
+static enum status_code _i2c_master_set_config(
+ struct i2c_master_module *const module,
+ const struct i2c_master_config *const config)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(config);
+
+ /* Temporary variables. */
+ uint32_t tmp_ctrla;
+ int32_t tmp_baud = 0;
+ int32_t tmp_baud_hs = 0;
+ int32_t tmp_baudlow_hs = 0;
+ enum status_code tmp_status_code = STATUS_OK;
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ Sercom *const sercom_hw = module->hw;
+
+ uint8_t sercom_index = _sercom_get_sercom_inst_index(sercom_hw);
+
+ /* Pin configuration */
+ struct system_pinmux_config pin_conf;
+ system_pinmux_get_config_defaults(&pin_conf);
+
+ uint32_t pad0 = config->pinmux_pad0;
+ uint32_t pad1 = config->pinmux_pad1;
+
+ /* SERCOM PAD0 - SDA */
+ if (pad0 == PINMUX_DEFAULT) {
+ pad0 = _sercom_get_default_pad(sercom_hw, 0);
+ }
+ pin_conf.mux_position = pad0 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad0 >> 16, &pin_conf);
+
+ /* SERCOM PAD1 - SCL */
+ if (pad1 == PINMUX_DEFAULT) {
+ pad1 = _sercom_get_default_pad(sercom_hw, 1);
+ }
+ pin_conf.mux_position = pad1 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad1 >> 16, &pin_conf);
+
+ /* Save timeout on unknown bus state in software module. */
+ module->unknown_bus_state_timeout = config->unknown_bus_state_timeout;
+
+ /* Save timeout on buffer write. */
+ module->buffer_timeout = config->buffer_timeout;
+
+ /* Set whether module should run in standby. */
+ if (config->run_in_standby || system_is_debugger_present()) {
+ tmp_ctrla = SERCOM_I2CM_CTRLA_RUNSTDBY;
+ } else {
+ tmp_ctrla = 0;
+ }
+
+ /* Check and set start data hold timeout. */
+ if (config->start_hold_time != I2C_MASTER_START_HOLD_TIME_DISABLED) {
+ tmp_ctrla |= config->start_hold_time;
+ }
+
+ /* Check and set transfer speed */
+ tmp_ctrla |= config->transfer_speed;
+
+ /* Check and set SCL low timeout. */
+ if (config->scl_low_timeout) {
+ tmp_ctrla |= SERCOM_I2CM_CTRLA_LOWTOUTEN;
+ }
+
+ /* Check and set inactive bus timeout. */
+ if (config->inactive_timeout != I2C_MASTER_INACTIVE_TIMEOUT_DISABLED) {
+ tmp_ctrla |= config->inactive_timeout;
+ }
+
+ /* Check and set SCL clock stretch mode. */
+ if (config->scl_stretch_only_after_ack_bit || (config->transfer_speed == I2C_MASTER_SPEED_HIGH_SPEED)) {
+ tmp_ctrla |= SERCOM_I2CM_CTRLA_SCLSM;
+ }
+
+ /* Check and set slave SCL low extend timeout. */
+ if (config->slave_scl_low_extend_timeout) {
+ tmp_ctrla |= SERCOM_I2CM_CTRLA_SEXTTOEN;
+ }
+
+ /* Check and set master SCL low extend timeout. */
+ if (config->master_scl_low_extend_timeout) {
+ tmp_ctrla |= SERCOM_I2CM_CTRLA_MEXTTOEN;
+ }
+
+ /* Write config to register CTRLA. */
+ i2c_module->CTRLA.reg |= tmp_ctrla;
+
+ /* Set configurations in CTRLB. */
+ i2c_module->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN;
+
+ /* Find and set baudrate, considering sda/scl rise time */
+ uint32_t fgclk = system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index);
+ uint32_t fscl = 1000 * config->baud_rate;
+ uint32_t fscl_hs = 1000 * config->baud_rate_high_speed;
+ uint32_t trise = config->sda_scl_rise_time_ns;
+
+ tmp_baud = (int32_t)(div_ceil(
+ fgclk - fscl * (10 + fgclk * trise * 0.000000001), 2 * fscl));
+
+ /* For High speed mode, set the SCL ratio of high:low to 1:2. */
+ if (config->transfer_speed == I2C_MASTER_SPEED_HIGH_SPEED) {
+ tmp_baudlow_hs = (int32_t)((fgclk * 2.0) / (3.0 * fscl_hs) - 1);
+ if (tmp_baudlow_hs) {
+ tmp_baud_hs = (int32_t)(fgclk / fscl_hs) - 2 - tmp_baudlow_hs;
+ } else {
+ tmp_baud_hs = (int32_t)(div_ceil(fgclk, 2 * fscl_hs)) - 1;
+ }
+ }
+
+ /* Check that baudrate is supported at current speed. */
+ if (tmp_baud > 255 || tmp_baud < 0 || tmp_baud_hs > 255 || tmp_baud_hs < 0) {
+ /* Baud rate not supported. */
+ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ }
+ if (tmp_status_code != STATUS_ERR_BAUDRATE_UNAVAILABLE) {
+ /* Baud rate acceptable. */
+ i2c_module->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud) |
+ SERCOM_I2CM_BAUD_HSBAUD(tmp_baud_hs) | SERCOM_I2CM_BAUD_HSBAUDLOW(tmp_baudlow_hs);
+ }
+
+ return tmp_status_code;
+}
+#endif /* __DOXYGEN__ */
+
+/**
+ * \brief Initializes the requested I<SUP>2</SUP>C hardware module
+ *
+ * Initializes the SERCOM I<SUP>2</SUP>C master device requested and sets the provided
+ * software module struct. Run this function before any further use of
+ * the driver.
+ *
+ * \param[out] module Pointer to software module struct
+ * \param[in] hw Pointer to the hardware instance
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return Status of initialization.
+ * \retval STATUS_OK Module initiated correctly
+ * \retval STATUS_ERR_DENIED If module is enabled
+ * \retval STATUS_BUSY If module is busy resetting
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible
+ * with set GCLK frequency
+ *
+ */
+enum status_code i2c_master_init(
+ struct i2c_master_module *const module,
+ Sercom *const hw,
+ const struct i2c_master_config *const config)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(hw);
+ Assert(config);
+
+ /* Initialize software module */
+ module->hw = hw;
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t pm_index, gclk_index;
+
+#if (SAML22) || (SAMC20)
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#elif (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+ pm_index = MCLK_APBDMASK_SERCOM5_Pos;
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+ } else {
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#elif (SAMC21)
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ if (sercom_index == 5) {
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+ } else {
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#else
+ pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#endif
+
+ /* Turn on module in PM */
+#if (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
+ } else {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+ }
+#else
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+#endif
+
+ /* Set up the GCLK for the module */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->generator_source;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->generator_source, false);
+
+ /* Check if module is enabled. */
+ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if reset is in progress. */
+ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) {
+ return STATUS_BUSY;
+ }
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Get sercom instance index and register callback. */
+ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
+ _sercom_set_handler(instance_index, _i2c_master_interrupt_handler);
+ _sercom_instances[instance_index] = module;
+
+ /* Initialize values in module. */
+ module->registered_callback = 0;
+ module->enabled_callback = 0;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ module->status = STATUS_OK;
+ module->buffer = NULL;
+#endif
+
+ /* Set sercom module to operate in I2C master mode. */
+ i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE(0x5);
+
+ /* Set config and return status. */
+ return _i2c_master_set_config(module, config);
+}
+
+/**
+ * \brief Resets the hardware module
+ *
+ * Reset the module to hardware defaults.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_master_reset(struct i2c_master_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Wait for sync */
+ _i2c_master_wait_for_sync(module);
+
+ /* Disable module */
+ i2c_master_disable(module);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Clear all pending interrupts */
+ system_interrupt_enter_critical_section();
+ system_interrupt_clear_pending(_sercom_get_interrupt_vector(module->hw));
+ system_interrupt_leave_critical_section();
+#endif
+
+ /* Wait for sync */
+ _i2c_master_wait_for_sync(module);
+
+ /* Reset module */
+ i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST;
+}
+
+#if !defined(__DOXYGEN__)
+/**
+ * \internal
+ * Address response. Called when address is answered or timed out.
+ *
+ * \param[in,out] module Pointer to software module structure
+ *
+ * \return Status of address response.
+ * \retval STATUS_OK No error has occurred
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code _i2c_master_address_response(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for error and ignore bus-error; workaround for BUSSTATE stuck in
+ * BUSY */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) {
+
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB;
+
+ /* Check arbitration. */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) {
+ /* Return packet collision. */
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+ /* Check that slave responded with ack. */
+ } else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Slave busy. Issue ack and stop command. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+
+ /* Return bad address value. */
+ return STATUS_ERR_BAD_ADDRESS;
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal
+ * Waits for answer on bus.
+ *
+ * \param[in,out] module Pointer to software module structure
+ *
+ * \return Status of bus.
+ * \retval STATUS_OK If given response from slave device
+ * \retval STATUS_ERR_TIMEOUT If no response was given within specified timeout
+ * period
+ */
+enum status_code _i2c_master_wait_for_bus(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Wait for reply. */
+ uint16_t timeout_counter = 0;
+ while (!(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) &&
+ !(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) {
+
+ /* Check timeout condition. */
+ if (++timeout_counter >= module->buffer_timeout) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ return STATUS_OK;
+}
+#endif /* __DOXYGEN__ */
+
+/**
+ * \internal
+ * Send master code for high speed transfer.
+ *
+ * \param[in,out] module Pointer to software module structure
+ * \param[in] hs_master_code 8-bit master code (0000 1XXX)
+ *
+ * \return Status of bus.
+ * \retval STATUS_OK No error happen
+ */
+enum status_code _i2c_master_send_hs_master_code(
+ struct i2c_master_module *const module,
+ uint8_t hs_master_code)
+{
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ /* Return value. */
+ enum status_code tmp_status;
+
+ /* Set NACK for high speed code */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ /* Send high speed code */
+ i2c_module->ADDR.reg = hs_master_code;
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB;
+
+ return tmp_status;
+}
+
+
+/**
+ * \internal
+ * Starts blocking read operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ *
+ */
+static enum status_code _i2c_master_read_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Return value. */
+ enum status_code tmp_status;
+ uint16_t tmp_data_length = packet->data_length;
+
+ /* Written buffer counter. */
+ uint16_t counter = 0;
+
+ bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM;
+
+ /* Switch to high speed mode */
+ if (packet->high_speed) {
+ _i2c_master_send_hs_master_code(module, packet->hs_master_code);
+ }
+
+ /* Set action to ACK. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Set address and direction bit. Will send start command on bus. */
+ if (packet->ten_bit_address) {
+ /*
+ * Write ADDR.ADDR[10:1] with the 10-bit address. ADDR.TENBITEN must
+ * be set and read/write bit (ADDR.ADDR[0]) equal to 0.
+ */
+ i2c_module->ADDR.reg = (packet->address << 1) |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ SERCOM_I2CM_ADDR_TENBITEN;
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Set action to ack. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ if (tmp_status == STATUS_OK) {
+ /*
+ * Write ADDR[7:0] register to "11110 address[9:8] 1"
+ * ADDR.TENBITEN must be cleared
+ */
+ i2c_module->ADDR.reg = (((packet->address >> 8) | 0x78) << 1) |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ I2C_TRANSFER_READ;
+ } else {
+ return tmp_status;
+ }
+ } else {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos);
+ }
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Set action to ack or nack. */
+ if ((sclsm_flag) && (packet->data_length == 1)) {
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ } else {
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ }
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ /* Check that no error has occurred. */
+ if (tmp_status == STATUS_OK) {
+ /* Read data buffer. */
+ while (tmp_data_length--) {
+ /* Check that bus ownership is not lost. */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+
+ if (module->send_nack && (((!sclsm_flag) && (tmp_data_length == 0)) ||
+ ((sclsm_flag) && (tmp_data_length == 1)))) {
+ /* Set action to NACK */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ } else {
+ /* Save data to buffer. */
+ _i2c_master_wait_for_sync(module);
+ packet->data[counter++] = i2c_module->DATA.reg;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+ }
+
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ break;
+ }
+ }
+
+ if (module->send_stop) {
+ /* Send stop command unless arbitration is lost. */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+
+ /* Save last data to buffer. */
+ _i2c_master_wait_for_sync(module);
+ packet->data[counter] = i2c_module->DATA.reg;
+ }
+
+ return tmp_status;
+}
+
+/**
+ * \brief Reads data packet from slave
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus and sends a stop condition when finished.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_packet_wait(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = true;
+ module->send_nack = true;
+
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Reads data packet from slave without sending a stop condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus without sending a stop condition when done, thus retaining ownership of
+ * the bus when done. To end the transaction, a
+ * \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_packet_wait_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = false;
+ module->send_nack = true;
+
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Starts blocking read operation.
+ * \brief Reads data packet from slave without sending a nack signal and a stop
+ * condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus without sending a nack signal and a stop condition when done,
+ * thus retaining ownership of the bus when done. To end the transaction, a
+ * \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_packet_wait_no_nack(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = false;
+ module->send_nack = false;
+
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Starts blocking write operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of write packet.
+ * \retval STATUS_OK The packet was write successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+static enum status_code _i2c_master_write_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Return value. */
+ enum status_code tmp_status;
+ uint16_t tmp_data_length = packet->data_length;
+
+ _i2c_master_wait_for_sync(module);
+
+ /* Switch to high speed mode */
+ if (packet->high_speed) {
+ _i2c_master_send_hs_master_code(module, packet->hs_master_code);
+ }
+
+ /* Set action to ACK. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Set address and direction bit. Will send start command on bus. */
+ if (packet->ten_bit_address) {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ SERCOM_I2CM_ADDR_TENBITEN;
+ } else {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos);
+ }
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ /* Check that no error has occurred. */
+ if (tmp_status == STATUS_OK) {
+ /* Buffer counter. */
+ uint16_t buffer_counter = 0;
+
+ /* Write data buffer. */
+ while (tmp_data_length--) {
+ /* Check that bus ownership is not lost. */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = packet->data[buffer_counter++];
+
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ break;
+ }
+
+ /* Check for NACK from slave. */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Return bad data value. */
+ tmp_status = STATUS_ERR_OVERFLOW;
+ break;
+ }
+ }
+
+ if (module->send_stop) {
+ /* Stop command */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+
+ return tmp_status;
+}
+
+/**
+ * \brief Writes data packet to slave
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus
+ * and sends a stop condition when finished.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of write packet.
+ * \retval STATUS_OK If packet was write successfully
+ * \retval STATUS_BUSY If master module is busy with a job
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ * \retval STATUS_ERR_TIMEOUT If timeout occurred
+ * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent
+ * data, indicating that slave does not
+ * want more data and was not able to read
+ * last data sent
+ */
+enum status_code i2c_master_write_packet_wait(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = true;
+ module->send_nack = true;
+
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Writes data packet to slave without sending a stop condition when done
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus
+ * without sending a stop condition, thus retaining ownership of the bus when
+ * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition or sending a
+ * stop with the \ref i2c_master_send_stop function must be performed.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of write packet.
+ * \retval STATUS_OK If packet was write successfully
+ * \retval STATUS_BUSY If master module is busy
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ * \retval STATUS_ERR_TIMEOUT If timeout occurred
+ * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent
+ * data, indicating that slave do not want
+ * more data
+ */
+enum status_code i2c_master_write_packet_wait_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = false;
+ module->send_nack = true;
+
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Sends stop condition on bus
+ *
+ * Sends a stop condition on bus.
+ *
+ * \note This function can only be used after the
+ * \ref i2c_master_write_packet_wait_no_stop function. If a stop condition
+ * is to be sent after a read, the \ref i2c_master_read_packet_wait
+ * function must be used.
+ *
+ * \param[in,out] module Pointer to the software instance struct
+ */
+void i2c_master_send_stop(struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Send stop command */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+}
+
+/**
+ * \brief Sends nack signal on bus
+ *
+ * Sends a nack signal on bus.
+ *
+ * \note This function can only be used after the
+ * \ref i2c_master_write_packet_wait_no_nack function,
+ * or \ref i2c_master_read_byte function.
+ * \param[in,out] module Pointer to the software instance struct
+ */
+void i2c_master_send_nack(struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Send nack signal */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+}
+
+/**
+ * \brief Reads one byte data from slave
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[out] byte Read one byte data to slave
+ *
+ * \return Status of reading byte.
+ * \retval STATUS_OK One byte was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_byte(
+ struct i2c_master_module *const module,
+ uint8_t *byte)
+{
+ enum status_code tmp_status;
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(module);
+ *byte = i2c_module->DATA.reg;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ return tmp_status;
+}
+
+/**
+ * \brief Write one byte data to slave
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in] byte Send one byte data to slave
+ *
+ * \return Status of writing byte.
+ * \retval STATUS_OK One byte was write successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_write_byte(
+ struct i2c_master_module *const module,
+ uint8_t byte)
+{
+ enum status_code tmp_status;
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = byte;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+ return tmp_status;
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c
new file mode 100644
index 000000000..7551b2912
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_master_interrupt.c
@@ -0,0 +1,762 @@
+/**
+ * \file
+ *
+ * \brief SAM I2C Master Interrupt Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_master_interrupt.h"
+
+extern enum status_code _i2c_master_wait_for_bus(
+ struct i2c_master_module *const module);
+
+extern enum status_code _i2c_master_address_response(
+ struct i2c_master_module *const module);
+
+extern enum status_code _i2c_master_send_hs_master_code(
+ struct i2c_master_module *const module,
+ uint8_t hs_master_code);;
+
+/**
+ * \internal
+ * Read next data. Used by interrupt handler to get next data byte from slave.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_read(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM;
+
+ /* Find index to save next value in buffer */
+ uint16_t buffer_index = module->buffer_length;
+ buffer_index -= module->buffer_remaining;
+
+ module->buffer_remaining--;
+
+ if (sclsm_flag) {
+ if (module->send_nack && module->buffer_remaining == 1) {
+ /* Set action to NACK. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ }
+ } else {
+ if (module->send_nack && module->buffer_remaining == 0) {
+ /* Set action to NACK. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ }
+ }
+
+ if (module->buffer_remaining == 0) {
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+
+ /* Read byte from slave and put in buffer */
+ _i2c_master_wait_for_sync(module);
+ module->buffer[buffer_index] = i2c_module->DATA.reg;
+}
+
+/**
+ * \internal
+ *
+ * Write next data. Used by interrupt handler to send next data byte to slave.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_write(struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for ack from slave */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK)
+ {
+ /* Set status */
+ module->status = STATUS_ERR_OVERFLOW;
+ /* Do not write more data */
+ return;
+ }
+
+ /* Find index to get next byte in buffer */
+ uint16_t buffer_index = module->buffer_length;
+ buffer_index -= module->buffer_remaining;
+
+ module->buffer_remaining--;
+
+ /* Write byte from buffer to slave */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = module->buffer[buffer_index];
+}
+
+/**
+ * \internal
+ * Acts on slave address response. Checks for errors concerning master->slave
+ * handshake.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_async_address_response(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for error. Ignore bus-error; workaround for bus state stuck in
+ * BUSY.
+ */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)
+ {
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB;
+
+ /* Check arbitration */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) {
+ /* Return busy */
+ module->status = STATUS_ERR_PACKET_COLLISION;
+ }
+ /* No slave responds */
+ else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ module->status = STATUS_ERR_BAD_ADDRESS;
+ module->buffer_remaining = 0;
+
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+ }
+
+ module->buffer_length = module->buffer_remaining;
+
+ /* Check for status OK. */
+ if (module->status == STATUS_BUSY) {
+ /* Call function based on transfer direction. */
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_master_write(module);
+ } else {
+ _i2c_master_read(module);
+ }
+ }
+}
+
+/**
+ * \brief Registers callback for the specified callback type
+ *
+ * Associates the given callback function with the
+ * specified callback type.
+ *
+ * To enable the callback, the \ref i2c_master_enable_callback function
+ * must be used.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback Pointer to the function desired for the
+ * specified callback
+ * \param[in] callback_type Callback type to register
+ */
+void i2c_master_register_callback(
+ struct i2c_master_module *const module,
+ const i2c_master_callback_t callback,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(callback);
+
+ /* Register callback */
+ module->callbacks[callback_type] = callback;
+
+ /* Set corresponding bit to set callback as registered */
+ module->registered_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters callback for the specified callback type
+ *
+ * When called, the currently registered callback for the given callback type
+ * will be removed.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Specifies the callback type to unregister
+ */
+void i2c_master_unregister_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Register callback */
+ module->callbacks[callback_type] = NULL;
+
+ /* Clear corresponding bit to set callback as unregistered */
+ module->registered_callback &= ~(1 << callback_type);
+}
+
+/**
+ * \internal
+ * Starts a read bytes operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_read_bytes(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_READ;
+ module->status = STATUS_BUSY;
+ module->send_stop = false;
+ module->send_nack = false;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal
+ * Starts a read packet operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+static enum status_code _i2c_master_read_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ enum status_code tmp_status;
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_READ;
+ module->status = STATUS_BUSY;
+
+ bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM;
+
+ /* Switch to high speed mode */
+ if (packet->high_speed) {
+ _i2c_master_send_hs_master_code(module, packet->hs_master_code);
+ }
+
+ /* Set action to ACK or NACK. */
+ if ((sclsm_flag) && (packet->data_length == 1)) {
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ } else {
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ }
+
+ if (packet->ten_bit_address) {
+ /*
+ * Write ADDR.ADDR[10:1] with the 10-bit address. ADDR.TENBITEN must
+ * be set and read/write bit (ADDR.ADDR[0]) equal to 0.
+ */
+ i2c_module->ADDR.reg = (packet->address << 1) |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ SERCOM_I2CM_ADDR_TENBITEN;
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Set action to ack. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ if (tmp_status == STATUS_OK) {
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /*
+ * Write ADDR[7:0] register to "11110 address[9:8] 1"
+ * ADDR.TENBITEN must be cleared
+ */
+ i2c_module->ADDR.reg = (((packet->address >> 8) | 0x78) << 1) |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ I2C_TRANSFER_READ;
+ } else {
+ return tmp_status;
+ }
+ } else {
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /* Set address and direction bit. Will send start command on bus */
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos);
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a read packet operation
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus. This is the non-blocking equivalent of \ref i2c_master_read_packet_wait.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_read_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we send STOP */
+ module->send_stop = true;
+ module->send_nack = true;
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a read packet operation without sending a STOP condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C bus without
+ * sending a stop condition, thus retaining ownership of the bus when done.
+ * To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another operation
+ */
+enum status_code i2c_master_read_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we don't send STOP */
+ module->send_stop = false;
+ module->send_nack = true;
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a read packet operation without sending a NACK signal and a
+ * STOP condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C bus without
+ * sending a nack and a stop condition, thus retaining ownership of the bus when done.
+ * To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another operation
+ */
+enum status_code i2c_master_read_packet_job_no_nack(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we don't send STOP */
+ module->send_stop = false;
+ module->send_nack = false;
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Starts a write bytes operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting write I<SUP>2</SUP>C bytes.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_write_bytes(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+ module->status = STATUS_BUSY;
+ module->send_stop = false;
+ module->send_nack = false;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal Initiates a write packet operation
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+static enum status_code _i2c_master_write_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Switch to high speed mode */
+ if (packet->high_speed) {
+ _i2c_master_send_hs_master_code(module, packet->hs_master_code);
+ }
+
+ /* Set action to ACK. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /* Set address and direction bit, will send start command on bus */
+ if (packet->ten_bit_address) {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) |
+ SERCOM_I2CM_ADDR_TENBITEN;
+ } else {
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE |
+ (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos);
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a write packet operation
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C
+ * bus. This is the non-blocking equivalent of \ref i2c_master_write_packet_wait.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_write_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with another job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we send STOP at end*/
+ module->send_stop = true;
+ module->send_nack = true;
+ /* Start write operation */
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a write packet operation without sending a STOP condition when done
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus
+ * without sending a stop condition, thus retaining ownership of the bus when
+ * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition or sending
+ * a stop with the \ref i2c_master_send_stop function must be performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_write_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another
+ */
+enum status_code i2c_master_write_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with another job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Do not send stop condition when done */
+ module->send_stop = false;
+ module->send_nack = true;
+ /* Start write operation */
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Interrupt handler for I<SUP>2</SUP>C master.
+ *
+ * \param[in] instance SERCOM instance that triggered the interrupt
+ */
+void _i2c_master_interrupt_handler(
+ uint8_t instance)
+{
+ /* Get software module for callback handling */
+ struct i2c_master_module *module =
+ (struct i2c_master_module*)_sercom_instances[instance];
+
+ Assert(module);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM;
+
+ /* Combine callback registered and enabled masks */
+ uint8_t callback_mask = module->enabled_callback;
+ callback_mask &= module->registered_callback;
+
+ /* Check if the module should respond to address ack */
+ if ((module->buffer_length <= 0) && (module->buffer_remaining > 0)) {
+ /* Call function for address response */
+ _i2c_master_async_address_response(module);
+
+ /* Check if buffer write is done */
+ } else if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) &&
+ (module->status == STATUS_BUSY) &&
+ (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg =
+ SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+
+ module->buffer_length = 0;
+ module->status = STATUS_OK;
+
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ } else {
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_MB;
+ }
+
+ if (callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE)) {
+ module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module);
+ }
+
+ /* Continue buffer write/read */
+ } else if ((module->buffer_length > 0) && (module->buffer_remaining > 0)){
+ /* Check that bus ownership is not lost */
+ if ((!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) &&
+ (!(sclsm_flag && (module->buffer_remaining == 1)))) {
+ module->status = STATUS_ERR_PACKET_COLLISION;
+ } else if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_master_write(module);
+ } else {
+ _i2c_master_read(module);
+ }
+ }
+
+ /* Check if read buffer transfer is complete */
+ if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) &&
+ (module->status == STATUS_BUSY) &&
+ (module->transfer_direction == I2C_TRANSFER_READ)) {
+
+ /* Clear read interrupt flag */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) {
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB;
+ }
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg =
+ SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+ module->buffer_length = 0;
+ module->status = STATUS_OK;
+
+ /* Call appropriate callback if enabled and registered */
+ if ((callback_mask & (1 << I2C_MASTER_CALLBACK_READ_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_READ)) {
+ module->callbacks[I2C_MASTER_CALLBACK_READ_COMPLETE](module);
+ } else if ((callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+
+ /* Check for error */
+ if ((module->status != STATUS_BUSY) && (module->status != STATUS_OK)) {
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB |
+ SERCOM_I2CM_INTENCLR_SB;
+
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ /* Send nack and stop command unless arbitration is lost */
+ if ((module->status != STATUS_ERR_PACKET_COLLISION) &&
+ module->send_stop) {
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT |
+ SERCOM_I2CM_CTRLB_CMD(3);
+ }
+
+ /* Call error callback if enabled and registered */
+ if (callback_mask & (1 << I2C_MASTER_CALLBACK_ERROR)) {
+ module->callbacks[I2C_MASTER_CALLBACK_ERROR](module);
+ }
+ }
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave.c
new file mode 100644
index 000000000..113087794
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave.c
@@ -0,0 +1,745 @@
+/**
+ * \file
+ *
+ * \brief SAM I2C Slave Driver
+ *
+ * Copyright (C) 2013-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_slave.h"
+#if I2C_SLAVE_CALLBACK_MODE == true
+# include "i2c_slave_interrupt.h"
+#endif
+
+/**
+ * \internal Sets configuration to module
+ *
+ * \param[out] module Pointer to software module structure
+ * \param[in] config Configuration structure with configurations to set
+ *
+ * \return Status of setting configuration.
+ * \retval STATUS_OK Module was configured correctly
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ */
+static enum status_code _i2c_slave_set_config(
+ struct i2c_slave_module *const module,
+ const struct i2c_slave_config *const config)
+{
+ uint32_t tmp_ctrla;
+
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(config);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ Sercom *const sercom_hw = module->hw;
+
+ module->buffer_timeout = config->buffer_timeout;
+ module->ten_bit_address = config->ten_bit_address;
+
+ struct system_pinmux_config pin_conf;
+ system_pinmux_get_config_defaults(&pin_conf);
+
+ uint32_t pad0 = config->pinmux_pad0;
+ uint32_t pad1 = config->pinmux_pad1;
+
+ /* SERCOM PAD0 - SDA */
+ if (pad0 == PINMUX_DEFAULT) {
+ pad0 = _sercom_get_default_pad(sercom_hw, 0);
+ }
+ pin_conf.mux_position = pad0 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad0 >> 16, &pin_conf);
+
+ /* SERCOM PAD1 - SCL */
+ if (pad1 == PINMUX_DEFAULT) {
+ pad1 = _sercom_get_default_pad(sercom_hw, 1);
+ }
+ pin_conf.mux_position = pad1 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad1 >> 16, &pin_conf);
+
+ /* Prepare config to write to register CTRLA */
+ if (config->run_in_standby || system_is_debugger_present()) {
+ tmp_ctrla = SERCOM_I2CS_CTRLA_RUNSTDBY;
+ } else {
+ tmp_ctrla = 0;
+ }
+
+ /* Check and set SCL clock stretch mode. */
+ if (config->scl_stretch_only_after_ack_bit || (config->transfer_speed == I2C_SLAVE_SPEED_HIGH_SPEED)) {
+ tmp_ctrla |= SERCOM_I2CM_CTRLA_SCLSM;
+ }
+
+ tmp_ctrla |= ((uint32_t)config->sda_hold_time |
+ config->transfer_speed |
+ (config->scl_low_timeout << SERCOM_I2CS_CTRLA_LOWTOUTEN_Pos) |
+ (config->slave_scl_low_extend_timeout << SERCOM_I2CS_CTRLA_SEXTTOEN_Pos));
+
+ i2c_hw->CTRLA.reg |= tmp_ctrla;
+
+ /* Set CTRLB configuration */
+ i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN | config->address_mode;
+
+ i2c_hw->ADDR.reg = config->address << SERCOM_I2CS_ADDR_ADDR_Pos |
+ config->address_mask << SERCOM_I2CS_ADDR_ADDRMASK_Pos |
+ config->ten_bit_address << SERCOM_I2CS_ADDR_TENBITEN_Pos |
+ config->enable_general_call_address << SERCOM_I2CS_ADDR_GENCEN_Pos;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initializes the requested I<SUP>2</SUP>C hardware module
+ *
+ * Initializes the SERCOM I<SUP>2</SUP>C slave device requested and sets the provided
+ * software module struct. Run this function before any further use of
+ * the driver.
+ *
+ * \param[out] module Pointer to software module struct
+ * \param[in] hw Pointer to the hardware instance
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return Status of initialization.
+ * \retval STATUS_OK Module initiated correctly
+ * \retval STATUS_ERR_DENIED If module is enabled
+ * \retval STATUS_BUSY If module is busy resetting
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ */
+enum status_code i2c_slave_init(
+ struct i2c_slave_module *const module,
+ Sercom *const hw,
+ const struct i2c_slave_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(hw);
+ Assert(config);
+
+ /* Initialize software module */
+ module->hw = hw;
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Check if module is enabled */
+ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_ENABLE) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if reset is in progress */
+ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_SWRST) {
+ return STATUS_BUSY;
+ }
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t pm_index, gclk_index;
+#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
+#if (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+ pm_index = MCLK_APBDMASK_SERCOM5_Pos;
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+ } else {
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#else
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#endif
+#else
+ pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#endif
+
+ /* Turn on module in PM */
+#if (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
+ } else {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+ }
+#else
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+#endif
+
+ /* Set up the GCLK for the module */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->generator_source;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->generator_source, false);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Get sercom instance index */
+ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
+
+ /* Save software module in interrupt handler */
+ _sercom_set_handler(instance_index, _i2c_slave_interrupt_handler);
+
+ /* Save software module */
+ _sercom_instances[instance_index] = module;
+
+ /* Initialize values in module */
+ module->registered_callback = 0;
+ module->enabled_callback = 0;
+ module->buffer_length = 0;
+ module->nack_on_address = config->enable_nack_on_address;
+#endif
+
+ /* Set SERCOM module to operate in I2C slave mode */
+ i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_MODE(0x4);
+
+ /* Set config and return status */
+ return _i2c_slave_set_config(module, config);
+}
+
+/**
+ * \brief Resets the hardware module
+ *
+ * This will reset the module to hardware defaults.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_slave_reset(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Reset module instance */
+ module->registered_callback = 0;
+ module->enabled_callback = 0;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+ module->buffer = NULL;
+#endif
+
+ /* Disable module */
+ i2c_slave_disable(module);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Clear all pending interrupts */
+ system_interrupt_enter_critical_section();
+ system_interrupt_clear_pending(_sercom_get_interrupt_vector(module->hw));
+ system_interrupt_leave_critical_section();
+#endif
+
+ /* Wait for sync */
+ _i2c_slave_wait_for_sync(module);
+
+ /* Reset module */
+ i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_SWRST;
+}
+
+/**
+ * \internal Waits for answer on bus
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Status of bus.
+ * \retval STATUS_OK If given response from slave device
+ * \retval STATUS_ERR_TIMEOUT If no response was given within specified timeout
+ * period
+ */
+static enum status_code _i2c_slave_wait_for_bus(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Wait for reply */
+ uint16_t timeout_counter = 0;
+ while ((!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY)) &&
+ (!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC)) &&
+ (!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH))) {
+
+ /* Check timeout condition */
+ if (++timeout_counter >= module->buffer_timeout) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Writes a packet to the master
+ *
+ * Writes a packet to the master. This will wait for the master to issue
+ * a request.
+ *
+ * \param[in] module Pointer to software module structure
+ * \param[in] packet Packet to write to master
+ *
+ * \return Status of packet write.
+ * \retval STATUS_OK Packet was written successfully
+ * \retval STATUS_ERR_DENIED Start condition not received, another
+ * interrupt flag is set
+ * \retval STATUS_ERR_IO There was an error in the previous transfer
+ * \retval STATUS_ERR_BAD_FORMAT Master wants to write data
+ * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) was provided
+ * \retval STATUS_ERR_BUSY The I<SUP>2</SUP>C module is busy with a job
+ * \retval STATUS_ERR_ERR_OVERFLOW Master NACKed before entire packet was
+ * transferred
+ * \retval STATUS_ERR_TIMEOUT No response was given within the timeout
+ * period
+ */
+enum status_code i2c_slave_write_packet_wait(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ uint16_t length = packet->data_length;
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Check if the module is busy with a job or AMATCH is enabled */
+ if (module->buffer_remaining > 0 ||
+ (i2c_hw->INTENSET.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ enum status_code status;
+ /* Wait for master to send address packet */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return STATUS_ERR_DENIED;
+ }
+
+ if (module->ten_bit_address) {
+ /* ACK the first address */
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+
+ /* Wait for address interrupt */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return STATUS_ERR_TIMEOUT;
+ }
+
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return STATUS_ERR_DENIED;
+ }
+ }
+
+ /* Check if there was an error in last transfer */
+ if (i2c_hw->STATUS.reg & (SERCOM_I2CS_STATUS_BUSERR |
+ SERCOM_I2CS_STATUS_COLL | SERCOM_I2CS_STATUS_LOWTOUT)) {
+ return STATUS_ERR_IO;
+ }
+
+ /* Check direction */
+ if (!(i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR)) {
+ /* Write request from master, send NACK and return */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+ return STATUS_ERR_BAD_FORMAT;
+ }
+
+ /* Read request from master, ACK address */
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+
+ uint16_t i = 0;
+
+ /* Wait for data interrupt */
+ status = _i2c_slave_wait_for_bus(module);
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ while (length--) {
+ /* Write data */
+ _i2c_slave_wait_for_sync(module);
+ i2c_hw->DATA.reg = packet->data[i++];
+
+ /* Wait for response from master */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_RXNACK &&
+ length !=0) {
+ /* NACK from master, abort */
+ /* Release line */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x02);
+
+ return STATUS_ERR_OVERFLOW;
+ }
+ /* ACK from master, continue writing */
+ }
+
+ /* Release line */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x02);
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Reads a packet from the master
+ *
+ * Reads a packet from the master. This will wait for the master to issue a
+ * request.
+ *
+ * \param[in] module Pointer to software module structure
+ * \param[out] packet Packet to read from master
+ *
+ * \return Status of packet read.
+ * \retval STATUS_OK Packet was read successfully
+ * \retval STATUS_ABORTED Master sent stop condition or repeated
+ * start before specified length of bytes
+ * was received
+ * \retval STATUS_ERR_IO There was an error in the previous transfer
+ * \retval STATUS_ERR_DENIED Start condition not received, another
+ * interrupt flag is set
+ * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) was provided
+ * \retval STATUS_ERR_BUSY The I<SUP>2</SUP>C module is busy with a job
+ * \retval STATUS_ERR_BAD_FORMAT Master wants to read data
+ * \retval STATUS_ERR_ERR_OVERFLOW Last byte received overflows buffer
+ */
+enum status_code i2c_slave_read_packet_wait(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ uint16_t length = packet->data_length;
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Check if the module is busy with a job or AMATCH is enabled */
+ if (module->buffer_remaining > 0 ||
+ (i2c_hw->INTENSET.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ enum status_code status;
+
+ /* Wait for master to send address packet */
+ status = _i2c_slave_wait_for_bus(module);
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if there was an error in the last transfer */
+ if (i2c_hw->STATUS.reg & (SERCOM_I2CS_STATUS_BUSERR |
+ SERCOM_I2CS_STATUS_COLL | SERCOM_I2CS_STATUS_LOWTOUT)) {
+ return STATUS_ERR_IO;
+ }
+ /* Check direction */
+ if ((i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR)) {
+ /* Read request from master, send NACK and return */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+ return STATUS_ERR_BAD_FORMAT;
+ }
+
+ /* Write request from master, ACK address */
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3);
+
+ uint16_t i = 0;
+ while (length--) {
+
+ /* Wait for next byte or stop condition */
+ status = _i2c_slave_wait_for_bus(module);
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ if ((i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) ||
+ i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ /* Master sent stop condition, or repeated start, read done */
+ /* Clear stop flag */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ return STATUS_ABORTED;
+ }
+
+ /* Read data */
+ _i2c_slave_wait_for_sync(module);
+ packet->data[i++] = i2c_hw->DATA.reg;
+
+ }
+
+ /* Packet read done, wait for packet to NACK, Stop or repeated start */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY) {
+ /* Buffer is full, send NACK */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_ACKACT;
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+ }
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) {
+ /* Clear stop flag */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Waits for a start condition on the bus
+ *
+ * \note This function is only available for 7-bit slave addressing.
+ *
+ * Waits for the master to issue a start condition on the bus.
+ *
+ * \note This function does not check for errors in the last transfer,
+ * this will be discovered when reading or writing.
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Direction of the current transfer, when in slave mode.
+ * \retval I2C_SLAVE_DIRECTION_NONE No request from master within timeout
+ * period
+ * \retval I2C_SLAVE_DIRECTION_READ Write request from master
+ * \retval I2C_SLAVE_DIRECTION_WRITE Read request from master
+ */
+enum i2c_slave_direction i2c_slave_get_direction_wait(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ enum status_code status;
+
+ /* Wait for address interrupt */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return I2C_SLAVE_DIRECTION_NONE;
+ }
+
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return I2C_SLAVE_DIRECTION_NONE;
+ }
+
+ /* Check direction */
+ if ((i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR)) {
+ /* Read request from master */
+ return I2C_SLAVE_DIRECTION_WRITE;
+ } else {
+ /* Write request from master */
+ return I2C_SLAVE_DIRECTION_READ;
+ }
+}
+
+/**
+ * \brief Retrieves the current module status
+ *
+ * Checks the status of the module and returns it as a bitmask of status
+ * flags.
+ *
+ * \param[in] module Pointer to the I<SUP>2</SUP>C slave software device struct
+ *
+ * \return Bitmask of status flags.
+ *
+ * \retval I2C_SLAVE_STATUS_ADDRESS_MATCH A valid address has been received
+ * \retval I2C_SLAVE_STATUS_DATA_READY A I<SUP>2</SUP>C slave byte transmission is
+ * successfully completed
+ * \retval I2C_SLAVE_STATUS_STOP_RECEIVED A stop condition is detected for a
+ * transaction being processed
+ * \retval I2C_SLAVE_STATUS_CLOCK_HOLD The slave is holding the SCL line
+ * low
+ * \retval I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT An SCL low time-out has occurred
+ * \retval I2C_SLAVE_STATUS_REPEATED_START Indicates a repeated start, only
+ * valid if \ref
+ * I2C_SLAVE_STATUS_ADDRESS_MATCH is
+ * set
+ * \retval I2C_SLAVE_STATUS_RECEIVED_NACK The last data packet sent was not
+ * acknowledged
+ * \retval I2C_SLAVE_STATUS_COLLISION The I<SUP>2</SUP>C slave was not able to
+ * transmit a high data or NACK bit
+ * \retval I2C_SLAVE_STATUS_BUS_ERROR An illegal bus condition has
+ * occurred on the bus
+ */
+uint32_t i2c_slave_get_status(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ uint8_t intflags = i2c_hw->INTFLAG.reg;
+ uint8_t status = i2c_hw->STATUS.reg;
+ uint32_t status_flags = 0;
+
+ /* Check Address Match flag */
+ if (intflags & SERCOM_I2CS_INTFLAG_AMATCH) {
+ status_flags |= I2C_SLAVE_STATUS_ADDRESS_MATCH;
+ }
+ /* Check Data Ready flag */
+ if (intflags & SERCOM_I2CS_INTFLAG_DRDY) {
+ status_flags |= I2C_SLAVE_STATUS_DATA_READY;
+ }
+ /* Check Stop flag */
+ if (intflags & SERCOM_I2CS_INTFLAG_PREC) {
+ status_flags |= I2C_SLAVE_STATUS_STOP_RECEIVED;
+ }
+ /* Check Clock Hold */
+ if (status & SERCOM_I2CS_STATUS_CLKHOLD) {
+ status_flags |= I2C_SLAVE_STATUS_CLOCK_HOLD;
+ }
+ /* Check SCL Low Timeout */
+ if (status & SERCOM_I2CS_STATUS_LOWTOUT) {
+ status_flags |= I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT;
+ }
+ /* Check Repeated Start */
+ if (status & SERCOM_I2CS_STATUS_SR) {
+ status_flags |= I2C_SLAVE_STATUS_REPEATED_START;
+ }
+ /* Check Received Not Acknowledge */
+ if (status & SERCOM_I2CS_STATUS_RXNACK) {
+ status_flags |= I2C_SLAVE_STATUS_RECEIVED_NACK;
+ }
+ /* Check Transmit Collision */
+ if (status & SERCOM_I2CS_STATUS_COLL) {
+ status_flags |= I2C_SLAVE_STATUS_COLLISION;
+ }
+ /* Check Bus Error */
+ if (status & SERCOM_I2CS_STATUS_BUSERR) {
+ status_flags |= I2C_SLAVE_STATUS_BUS_ERROR;
+ }
+
+ return status_flags;
+}
+
+/**
+ * \brief Clears a module status flag
+ *
+ * Clears the given status flag of the module.
+ *
+ * \note Not all status flags can be cleared.
+ *
+ * \param[in] module Pointer to the I<SUP>2</SUP>C software device struct
+ * \param[in] status_flags Bit mask of status flags to clear
+ *
+ */
+void i2c_slave_clear_status(
+ struct i2c_slave_module *const module,
+ uint32_t status_flags)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Clear Address Match flag */
+ if (status_flags & I2C_SLAVE_STATUS_ADDRESS_MATCH) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+ /* Clear Data Ready flag */
+ if (status_flags & I2C_SLAVE_STATUS_DATA_READY) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_DRDY;
+ }
+ /* Clear Stop flag */
+ if (status_flags & I2C_SLAVE_STATUS_STOP_RECEIVED) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ }
+ /* Clear SCL Low Timeout */
+ if (status_flags & I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT) {
+ i2c_hw->STATUS.reg = SERCOM_I2CS_STATUS_LOWTOUT;
+ }
+ /* Clear Transmit Collision */
+ if (status_flags & I2C_SLAVE_STATUS_COLLISION) {
+ i2c_hw->STATUS.reg = SERCOM_I2CS_STATUS_COLL;
+ }
+ /* Clear Bus Error */
+ if (status_flags & I2C_SLAVE_STATUS_BUS_ERROR) {
+ i2c_hw->STATUS.reg = SERCOM_I2CS_STATUS_BUSERR;
+ }
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave_interrupt.c
new file mode 100644
index 000000000..0a6f234f8
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_sam0/i2c_slave_interrupt.c
@@ -0,0 +1,434 @@
+/**
+ * \file
+ *
+ * \brief SAM I2C Slave Interrupt Driver
+ *
+ * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_slave_interrupt.h"
+
+/**
+ * \brief Enables sending of NACK on address match
+ *
+ * Enables sending of NACK on address match, thus discarding
+ * any incoming transaction.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_slave_enable_nack_on_address(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+
+ module->nack_on_address = true;
+}
+
+/**
+ * \brief Disables sending NACK on address match
+ *
+ * Disables sending of NACK on address match, thus
+ * acknowledging incoming transactions.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_slave_disable_nack_on_address(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+
+ module->nack_on_address = false;
+}
+
+/**
+ * \internal
+ * Reads next data. Used by interrupt handler to get next data byte from master.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_slave_read(
+ struct i2c_slave_module *const module)
+{
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Read byte from master and put in buffer. */
+ *(module->buffer++) = i2c_hw->DATA.reg;
+
+ /*Decrement remaining buffer length */
+ module->buffer_remaining--;
+}
+
+/**
+ * \internal
+ * Writes next data. Used by interrupt handler to send next data byte to master.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_slave_write(
+ struct i2c_slave_module *const module)
+{
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Write byte from buffer to master */
+ i2c_hw->DATA.reg = *(module->buffer++);
+
+ /*Decrement remaining buffer length */
+ module->buffer_remaining--;
+}
+
+/**
+ * \brief Registers callback for the specified callback type
+ *
+ * Associates the given callback function with the
+ * specified callback type. To enable the callback, the
+ * \ref i2c_slave_enable_callback function must be used.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback Pointer to the function desired for the
+ * specified callback
+ * \param[in] callback_type Callback type to register
+ */
+void i2c_slave_register_callback(
+ struct i2c_slave_module *const module,
+ i2c_slave_callback_t callback,
+ enum i2c_slave_callback callback_type)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(callback);
+
+ /* Register callback. */
+ module->callbacks[callback_type] = callback;
+
+ /* Set corresponding bit to set callback as initiated. */
+ module->registered_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters callback for the specified callback type
+ *
+ * Removes the currently registered callback for the given callback
+ * type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to unregister
+ */
+void i2c_slave_unregister_callback(
+ struct i2c_slave_module *const module,
+ enum i2c_slave_callback callback_type)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Register callback. */
+ module->callbacks[callback_type] = NULL;
+
+ /* Set corresponding bit to set callback as initiated. */
+ module->registered_callback &= ~(1 << callback_type);
+}
+
+/**
+ * \brief Initiates a reads packet operation
+ *
+ * Reads a data packet from the master. A write request must be initiated by
+ * the master before the packet can be read.
+ *
+ * The \ref I2C_SLAVE_CALLBACK_WRITE_REQUEST callback can be used to call this
+ * function.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting asynchronously reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_slave_read_packet_job(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy doing async operation. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Save packet to software module. */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->buffer_length = packet->data_length;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ i2c_hw->INTENSET.reg = SERCOM_I2CS_INTFLAG_AMATCH |
+ SERCOM_I2CS_INTFLAG_DRDY | SERCOM_I2CS_INTFLAG_PREC;
+
+ /* Read will begin when master initiates the transfer */
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a write packet operation
+ *
+ * Writes a data packet to the master. A read request must be initiated by
+ * the master before the packet can be written.
+ *
+ * The \ref I2C_SLAVE_CALLBACK_READ_REQUEST callback can be used to call this
+ * function.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_slave_write_packet_job(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy doing async operation. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Save packet to software module. */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->buffer_length = packet->data_length;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ i2c_hw->INTENSET.reg = SERCOM_I2CS_INTFLAG_AMATCH |
+ SERCOM_I2CS_INTFLAG_DRDY | SERCOM_I2CS_INTFLAG_PREC;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal Interrupt handler for I<SUP>2</SUP>C slave
+ *
+ * \param[in] instance Sercom instance that triggered the interrupt
+ */
+void _i2c_slave_interrupt_handler(
+ uint8_t instance)
+{
+ /* Get software module for callback handling. */
+ struct i2c_slave_module *module =
+ (struct i2c_slave_module*)_sercom_instances[instance];
+
+ Assert(module);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Combine callback registered and enabled masks. */
+ uint8_t callback_mask = module->enabled_callback;
+ callback_mask &= module->registered_callback;
+
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ /* Address match */
+ /* Check if last transfer is done - repeated start */
+ if (module->buffer_length != module->buffer_remaining &&
+ module->transfer_direction == I2C_TRANSFER_WRITE) {
+
+ module->status = STATUS_OK;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE))) {
+ module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
+ }
+ } else if (module->buffer_length != module->buffer_remaining &&
+ module->transfer_direction == I2C_TRANSFER_READ) {
+ module->status = STATUS_OK;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_COMPLETE))) {
+ module->callbacks[I2C_SLAVE_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+
+ if (i2c_hw->STATUS.reg & (SERCOM_I2CS_STATUS_BUSERR |
+ SERCOM_I2CS_STATUS_COLL | SERCOM_I2CS_STATUS_LOWTOUT)) {
+ /* An error occurred in last packet transfer */
+ module->status = STATUS_ERR_IO;
+
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_ERROR_LAST_TRANSFER))) {
+ module->callbacks[I2C_SLAVE_CALLBACK_ERROR_LAST_TRANSFER](module);
+ }
+ }
+ if (module->nack_on_address) {
+ /* NACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ } else if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR) {
+ /* Set transfer direction in module instance */
+ module->transfer_direction = I2C_TRANSFER_READ;
+
+ /* Read request from master */
+ if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_REQUEST)) {
+ module->callbacks[I2C_SLAVE_CALLBACK_READ_REQUEST](module);
+ }
+
+ if (module->buffer_length == 0) {
+ /* Data buffer not set up, NACK address, workaround 13574*/
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ } else {
+ /* ACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+ }
+ } else {
+ /* Set transfer direction in dev inst */
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+
+ /* Write request from master */
+ if (callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_REQUEST)) {
+ module->callbacks[I2C_SLAVE_CALLBACK_WRITE_REQUEST](module);
+ }
+
+ if (module->buffer_length == 0) {
+ /* Data buffer not set up, NACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ } else {
+ /* ACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+ }
+ }
+
+ /* ACK or NACK address, Workaround 13574 */
+ _i2c_slave_set_ctrlb_cmd3(module);
+
+ /* ACK next incoming packet, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+
+ } else if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) {
+ /* Stop condition on bus - current transfer done */
+
+ /* Clear Stop interrupt */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+
+ /* Disable interrupts */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_PREC | SERCOM_I2CS_INTFLAG_DRDY;
+
+ if (!((module->enabled_callback & (1 << I2C_SLAVE_CALLBACK_READ_REQUEST))
+ || (module->enabled_callback == (1 << I2C_SLAVE_CALLBACK_WRITE_REQUEST)))) {
+ /* Disable address match if read/write request is not enabled */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+
+ if (!(module->status == STATUS_ERR_OVERFLOW || module->status == STATUS_ERR_IO)) {
+ module->status = STATUS_OK;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ /* Call appropriate callback if enabled and registered */
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ /* Read from master complete */
+ module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
+ } else if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_READ)) {
+ /* Write to master complete */
+ module->callbacks[I2C_SLAVE_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+ } else if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY) {
+ /* Check if buffer is full, or NACK from master */
+ if (module->buffer_remaining <= 0 ||
+ (module->transfer_direction == I2C_TRANSFER_READ &&
+ (module->buffer_length > module->buffer_remaining) &&
+ (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_RXNACK))) {
+
+ module->buffer_remaining = 0;
+ module->buffer_length = 0;
+
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ /* Buffer is full, send NACK, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+
+ /* Set status, new character in DATA register will overflow
+ * buffer */
+ module->status = STATUS_ERR_OVERFLOW;
+
+ if (callback_mask & (1 << I2C_SLAVE_CALLBACK_ERROR)) {
+ /* Read complete */
+ module->callbacks[I2C_SLAVE_CALLBACK_ERROR](module);
+ }
+ } else {
+ /* Release SCL and wait for new start condition */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+
+ /* Transfer successful */
+ module->status = STATUS_OK;
+
+ /* Disable interrupts */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_DRDY;
+ }
+
+ /* Continue buffer write/read */
+ } else if (module->buffer_length > 0 && module->buffer_remaining > 0) {
+ /* Call function based on transfer direction */
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_slave_read(module);
+ } else {
+ _i2c_slave_write(module);
+ }
+ }
+ }
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master.c
new file mode 100644
index 000000000..ce4f58c23
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master.c
@@ -0,0 +1,881 @@
+/**
+ * \file
+ *
+ * \brief SAM D20 I2C Master Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_master.h"
+
+#if I2C_MASTER_CALLBACK_MODE == true
+# include "i2c_master_interrupt.h"
+#endif
+
+#if !defined(__DOXYGEN__)
+
+/**
+ * \internal Sets configurations to module
+ *
+ * \param[out] module Pointer to software module structure
+ * \param[in] config Configuration structure with configurations to set
+ *
+ * \return Status of setting configuration.
+ * \retval STATUS_OK If module was configured correctly
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baud rate is not compatible
+ * with set GCLK frequency
+ */
+static enum status_code _i2c_master_set_config(
+ struct i2c_master_module *const module,
+ const struct i2c_master_config *const config)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(config);
+
+ /* Temporary variables. */
+ uint32_t tmp_ctrla;
+ int32_t tmp_baud;
+ enum status_code tmp_status_code = STATUS_OK;
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+ Sercom *const sercom_hw = module->hw;
+
+ uint8_t sercom_index = _sercom_get_sercom_inst_index(sercom_hw);
+
+ /* Pin configuration */
+ struct system_pinmux_config pin_conf;
+ system_pinmux_get_config_defaults(&pin_conf);
+
+ uint32_t pad0 = config->pinmux_pad0;
+ uint32_t pad1 = config->pinmux_pad1;
+
+ /* SERCOM PAD0 - SDA */
+ if (pad0 == PINMUX_DEFAULT) {
+ pad0 = _sercom_get_default_pad(sercom_hw, 0);
+ }
+ pin_conf.mux_position = pad0 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad0 >> 16, &pin_conf);
+
+ /* SERCOM PAD1 - SCL */
+ if (pad1 == PINMUX_DEFAULT) {
+ pad1 = _sercom_get_default_pad(sercom_hw, 1);
+ }
+ pin_conf.mux_position = pad1 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad1 >> 16, &pin_conf);
+
+ /* Save timeout on unknown bus state in software module. */
+ module->unknown_bus_state_timeout = config->unknown_bus_state_timeout;
+
+ /* Save timeout on buffer write. */
+ module->buffer_timeout = config->buffer_timeout;
+
+ /* Set whether module should run in standby. */
+ if (config->run_in_standby || system_is_debugger_present()) {
+ tmp_ctrla = SERCOM_I2CM_CTRLA_RUNSTDBY;
+ } else {
+ tmp_ctrla = 0;
+ }
+
+ /* Check and set start data hold timeout. */
+ if (config->start_hold_time != I2C_MASTER_START_HOLD_TIME_DISABLED) {
+ tmp_ctrla |= config->start_hold_time;
+ }
+
+ /* Check and set SCL low timeout. */
+ if (config->scl_low_timeout) {
+ tmp_ctrla |= SERCOM_I2CM_CTRLA_LOWTOUT;
+ }
+
+ /* Check and set inactive bus timeout. */
+ if (config->inactive_timeout != I2C_MASTER_INACTIVE_TIMEOUT_DISABLED) {
+ tmp_ctrla |= config->inactive_timeout;
+ }
+
+ /* Write config to register CTRLA. */
+ i2c_module->CTRLA.reg |= tmp_ctrla;
+
+ /* Set configurations in CTRLB. */
+ i2c_module->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN;
+
+ /* Find and set baudrate. */
+ tmp_baud = (int32_t)(div_ceil(
+ system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index),
+ (2000*(config->baud_rate))) - 5);
+
+ /* Check that baud rate is supported at current speed. */
+ if (tmp_baud > 255 || tmp_baud < 0) {
+ /* Baud rate not supported. */
+ tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ } else {
+ /* Baud rate acceptable. */
+ i2c_module->BAUD.reg = (uint8_t)tmp_baud;
+ }
+
+ return tmp_status_code;
+}
+#endif /* __DOXYGEN__ */
+
+/**
+ * \brief Initializes the requested I<SUP>2</SUP>C hardware module
+ *
+ * Initializes the SERCOM I<SUP>2</SUP>C master device requested and sets the provided
+ * software module struct. Run this function before any further use of
+ * the driver.
+ *
+ * \param[out] module Pointer to software module struct
+ * \param[in] hw Pointer to the hardware instance
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return Status of initialization.
+ * \retval STATUS_OK Module initiated correctly
+ * \retval STATUS_ERR_DENIED If module is enabled
+ * \retval STATUS_BUSY If module is busy resetting
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible
+ * with set GCLK frequency
+ *
+ */
+enum status_code i2c_master_init(
+ struct i2c_master_module *const module,
+ Sercom *const hw,
+ const struct i2c_master_config *const config)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(hw);
+ Assert(config);
+
+ /* Initialize software module */
+ module->hw = hw;
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+ uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+
+ /* Turn on module in PM */
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+
+ /* Set up the GCLK for the module */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->generator_source;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->generator_source, false);
+
+ /* Check if module is enabled. */
+ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if reset is in progress. */
+ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) {
+ return STATUS_BUSY;
+ }
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Get sercom instance index and register callback. */
+ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
+ _sercom_set_handler(instance_index, _i2c_master_interrupt_handler);
+ _sercom_instances[instance_index] = module;
+
+ /* Initialize values in module. */
+ module->registered_callback = 0;
+ module->enabled_callback = 0;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ module->status = STATUS_OK;
+ module->buffer = NULL;
+#endif
+
+ /* Set sercom module to operate in I2C master mode. */
+ i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER;
+
+ /* Set config and return status. */
+ return _i2c_master_set_config(module, config);
+}
+
+/**
+ * \brief Resets the hardware module
+ *
+ * Reset the module to hardware defaults.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_master_reset(struct i2c_master_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Wait for sync */
+ _i2c_master_wait_for_sync(module);
+
+ /* Disable module */
+ i2c_master_disable(module);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Clear all pending interrupts */
+ system_interrupt_enter_critical_section();
+ system_interrupt_clear_pending(_sercom_get_interrupt_vector(module->hw));
+ system_interrupt_leave_critical_section();
+#endif
+
+ /* Wait for sync */
+ _i2c_master_wait_for_sync(module);
+
+ /* Reset module */
+ i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST;
+}
+
+#if !defined(__DOXYGEN__)
+/**
+ * \internal
+ * Address response. Called when address is answered or timed out.
+ *
+ * \param[in,out] module Pointer to software module structure
+ *
+ * \return Status of address response.
+ * \retval STATUS_OK No error has occurred
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+static enum status_code _i2c_master_address_response(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for error and ignore bus-error; workaround for BUSSTATE stuck in
+ * BUSY */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) {
+
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB;
+
+ /* Check arbitration. */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) {
+ /* Return packet collision. */
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+ /* Check that slave responded with ack. */
+ } else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Slave busy. Issue ack and stop command. */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+
+ /* Return bad address value. */
+ return STATUS_ERR_BAD_ADDRESS;
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal
+ * Waits for answer on bus.
+ *
+ * \param[in,out] module Pointer to software module structure
+ *
+ * \return Status of bus.
+ * \retval STATUS_OK If given response from slave device
+ * \retval STATUS_ERR_TIMEOUT If no response was given within specified timeout
+ * period
+ */
+static enum status_code _i2c_master_wait_for_bus(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Wait for reply. */
+ uint16_t timeout_counter = 0;
+ while (!(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) &&
+ !(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) {
+
+ /* Check timeout condition. */
+ if (++timeout_counter >= module->buffer_timeout) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ return STATUS_OK;
+}
+#endif /* __DOXYGEN__ */
+
+/**
+ * \internal
+ * Starts blocking read operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ *
+ */
+static enum status_code _i2c_master_read_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Return value. */
+ enum status_code tmp_status;
+ uint16_t tmp_data_length = packet->data_length;
+
+ /* Written buffer counter. */
+ uint16_t counter = 0;
+
+ /* Set address and direction bit. Will send start command on bus. */
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ;
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Set action to ack. */
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ /* Check that no error has occurred. */
+ if (tmp_status == STATUS_OK) {
+ /* Read data buffer. */
+ while (tmp_data_length--) {
+ /* Check that bus ownership is not lost. */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+
+ if (module->send_nack && tmp_data_length == 0) {
+ /* Set action to NACK */
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ } else {
+ /* Save data to buffer. */
+ _i2c_master_wait_for_sync(module);
+ packet->data[counter++] = i2c_module->DATA.reg;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+ }
+
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ break;
+ }
+ }
+
+ if (module->send_stop) {
+ /* Send stop command unless arbitration is lost. */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ } else {
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(1);
+ }
+
+ /* Save last data to buffer. */
+ _i2c_master_wait_for_sync(module);
+ packet->data[counter] = i2c_module->DATA.reg;
+ }
+
+ return tmp_status;
+}
+
+/**
+ * \brief Reads data packet from slave
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus and sends a stop condition when finished.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_packet_wait(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = true;
+ module->send_nack = true;
+
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Reads data packet from slave without sending a stop condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus without sending a stop condition when done, thus retaining ownership of
+ * the bus when done. To end the transaction, a
+ * \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_packet_wait_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = false;
+ module->send_nack = true;
+
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Starts blocking read operation.
+ * \brief Reads data packet from slave without sending a nack signal and a stop
+ * condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus without sending a nack signal and a stop condition when done,
+ * thus retaining ownership of the bus when done. To end the transaction, a
+ * \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of reading packet.
+ * \retval STATUS_OK The packet was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_packet_wait_no_nack(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = false;
+ module->send_nack = false;
+
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Starts blocking write operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of write packet.
+ * \retval STATUS_OK The packet was write successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+static enum status_code _i2c_master_write_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Return value. */
+ enum status_code tmp_status;
+ uint16_t tmp_data_length = packet->data_length;
+
+ _i2c_master_wait_for_sync(module);
+
+ /* Set address and direction bit. Will send start command on bus. */
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE;
+
+ /* Wait for response on bus. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Check for address response error unless previous error is
+ * detected. */
+ if (tmp_status == STATUS_OK) {
+ tmp_status = _i2c_master_address_response(module);
+ }
+
+ /* Check that no error has occurred. */
+ if (tmp_status == STATUS_OK) {
+ /* Buffer counter. */
+ uint16_t buffer_counter = 0;
+
+ /* Write data buffer. */
+ while (tmp_data_length--) {
+ /* Check that bus ownership is not lost. */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = packet->data[buffer_counter++];
+
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ /* Check for error. */
+ if (tmp_status != STATUS_OK) {
+ break;
+ }
+
+ /* Check for NACK from slave. */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Return bad data value. */
+ tmp_status = STATUS_ERR_OVERFLOW;
+ break;
+ }
+ }
+
+ if (module->send_stop) {
+ /* Stop command */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+
+ return tmp_status;
+}
+
+/**
+ * \brief Writes data packet to slave
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus
+ * and sends a stop condition when finished.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of write packet.
+ * \retval STATUS_OK If packet was write successfully
+ * \retval STATUS_BUSY If master module is busy with a job
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ * \retval STATUS_ERR_TIMEOUT If timeout occurred
+ * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent
+ * data, indicating that slave does not
+ * want more data and was not able to read
+ * last data sent
+ */
+enum status_code i2c_master_write_packet_wait(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = true;
+ module->send_nack = true;
+
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Writes data packet to slave without sending a stop condition when done
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus
+ * without sending a stop condition, thus retaining ownership of the bus when
+ * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition or sending a
+ * stop with the \ref i2c_master_send_stop function must be performed.
+ *
+ * \note This will stall the device from any other operation. For
+ * interrupt-driven operation, see \ref i2c_master_read_packet_job.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of write packet.
+ * \retval STATUS_OK If packet was write successfully
+ * \retval STATUS_BUSY If master module is busy
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ * \retval STATUS_ERR_TIMEOUT If timeout occurred
+ * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent
+ * data, indicating that slave do not want
+ * more data
+ */
+enum status_code i2c_master_write_packet_wait_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+#if I2C_MASTER_CALLBACK_MODE == true
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ module->send_stop = false;
+ module->send_nack = true;
+
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Sends stop condition on bus
+ *
+ * Sends a stop condition on bus.
+ *
+ * \note This function can only be used after the
+ * \ref i2c_master_write_packet_wait_no_stop function. If a stop condition
+ * is to be sent after a read, the \ref i2c_master_read_packet_wait
+ * function must be used.
+ *
+ * \param[in,out] module Pointer to the software instance struct
+ */
+void i2c_master_send_stop(struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Send stop command */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+}
+
+/**
+ * \brief Sends nack signal on bus
+ *
+ * Sends a nack signal on bus.
+ *
+ * \note This function can only be used after the
+ * \ref i2c_master_write_packet_wait_no_nack function,
+ * or \ref i2c_master_read_byte function.
+ * \param[in,out] module Pointer to the software instance struct
+ */
+void i2c_master_send_nack(struct i2c_master_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Send nack signal */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+}
+
+/**
+ * \brief Reads one byte data from slave
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[out] byte Read one byte data to slave
+ *
+ * \return Status of reading byte.
+ * \retval STATUS_OK One byte was read successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_read_byte(
+ struct i2c_master_module *const module,
+ uint8_t *byte)
+{
+ enum status_code tmp_status;
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(module);
+ *byte = i2c_module->DATA.reg;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+
+ return tmp_status;
+}
+
+/**
+ * \brief Write one byte data to slave
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in] byte Send one byte data to slave
+ *
+ * \return Status of writing byte.
+ * \retval STATUS_OK One byte was write successfully
+ * \retval STATUS_ERR_TIMEOUT If no response was given within
+ * specified timeout period
+ * \retval STATUS_ERR_DENIED If error on bus
+ * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost
+ * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave
+ * acknowledged the address
+ */
+enum status_code i2c_master_write_byte(
+ struct i2c_master_module *const module,
+ uint8_t byte)
+{
+ enum status_code tmp_status;
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Write byte to slave. */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = byte;
+ /* Wait for response. */
+ tmp_status = _i2c_master_wait_for_bus(module);
+ return tmp_status;
+} \ No newline at end of file
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master_interrupt.c
new file mode 100644
index 000000000..07c892a03
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_master_interrupt.c
@@ -0,0 +1,670 @@
+/**
+ * \file
+ *
+ * \brief SAM D20 I2C Master Interrupt Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_master_interrupt.h"
+
+/**
+ * \internal
+ * Read next data. Used by interrupt handler to get next data byte from slave.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_read(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Find index to save next value in buffer */
+ uint16_t buffer_index = module->buffer_length - module->buffer_remaining;
+
+ module->buffer_remaining--;
+
+ if (!module->buffer_remaining) {
+ /* Send nack */
+ if (module->send_nack)
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT;
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ } else {
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(1);
+ }
+ } else {
+ i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT;
+ }
+
+ /* Read byte from slave and put in buffer */
+ _i2c_master_wait_for_sync(module);
+ module->buffer[buffer_index] = i2c_module->DATA.reg;
+}
+
+/**
+ * \internal
+ *
+ * Write next data. Used by interrupt handler to send next data byte to slave.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_write(struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for ack from slave */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK)
+ {
+ /* Set status */
+ module->status = STATUS_ERR_OVERFLOW;
+ /* Do not write more data */
+ return;
+ }
+
+ /* Find index to get next byte in buffer */
+ uint16_t buffer_index = module->buffer_length - module->buffer_remaining;
+
+ module->buffer_remaining--;
+
+ /* Write byte from buffer to slave */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->DATA.reg = module->buffer[buffer_index];
+}
+
+/**
+ * \internal
+ * Acts on slave address response. Checks for errors concerning master->slave
+ * handshake.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_master_async_address_response(
+ struct i2c_master_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Check for error. Ignore bus-error; workaround for bus state stuck in
+ * BUSY.
+ */
+ if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)
+ {
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB;
+
+ /* Check arbitration */
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) {
+ /* Return busy */
+ module->status = STATUS_ERR_PACKET_COLLISION;
+ }
+ }
+
+ if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
+ /* Return bad address value */
+ module->status = STATUS_ERR_BAD_ADDRESS;
+ module->buffer_remaining = 0;
+
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ }
+ }
+
+ module->buffer_length = module->buffer_remaining;
+
+ /* Check for status OK. */
+ if (module->status == STATUS_BUSY) {
+ /* Call function based on transfer direction. */
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_master_write(module);
+ } else {
+ _i2c_master_read(module);
+ }
+ }
+}
+
+/**
+ * \brief Registers callback for the specified callback type
+ *
+ * Associates the given callback function with the
+ * specified callback type.
+ *
+ * To enable the callback, the \ref i2c_master_enable_callback function
+ * must be used.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback Pointer to the function desired for the
+ * specified callback
+ * \param[in] callback_type Callback type to register
+ */
+void i2c_master_register_callback(
+ struct i2c_master_module *const module,
+ const i2c_master_callback_t callback,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(callback);
+
+ /* Register callback */
+ module->callbacks[callback_type] = callback;
+
+ /* Set corresponding bit to set callback as registered */
+ module->registered_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters callback for the specified callback type
+ *
+ * When called, the currently registered callback for the given callback type
+ * will be removed.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Specifies the callback type to unregister
+ */
+void i2c_master_unregister_callback(
+ struct i2c_master_module *const module,
+ enum i2c_master_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Register callback */
+ module->callbacks[callback_type] = NULL;
+
+ /* Clear corresponding bit to set callback as unregistered */
+ module->registered_callback &= ~(1 << callback_type);
+}
+
+/**
+ * \internal
+ * Starts a read bytes operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_read_bytes(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_READ;
+ module->status = STATUS_BUSY;
+ module->send_stop = false;
+ module->send_nack = false;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal
+ * Starts a read packet operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+static enum status_code _i2c_master_read_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_READ;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /* Set address and direction bit. Will send start command on bus */
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a read packet operation
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C
+ * bus. This is the non-blocking equivalent of \ref i2c_master_read_packet_wait.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_read_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we send STOP */
+ module->send_stop = true;
+ module->send_nack = true;
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a read packet operation without sending a STOP condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C bus without
+ * sending a stop condition, thus retaining ownership of the bus when done.
+ * To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another operation
+ */
+enum status_code i2c_master_read_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we don't send STOP */
+ module->send_stop = false;
+ module->send_nack = true;
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a read packet operation without sending a NACK signal and a
+ * STOP condition when done
+ *
+ * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C bus without
+ * sending a nack and a stop condition, thus retaining ownership of the bus when done.
+ * To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition must be
+ * performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_read_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another operation
+ */
+enum status_code i2c_master_read_packet_job_no_nack(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with a job */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we don't send STOP */
+ module->send_stop = false;
+ module->send_nack = false;
+ /* Start reading */
+ return _i2c_master_read_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Starts a write bytes operation.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting write I<SUP>2</SUP>C bytes.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_write_bytes(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+ module->status = STATUS_BUSY;
+ module->send_stop = false;
+ module->send_nack = false;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal Initiates a write packet operation
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+static enum status_code _i2c_master_write_packet(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Save packet to software module */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ i2c_module->INTENSET.reg =
+ SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB;
+
+ /* Set address and direction bit, will send start command on bus */
+ i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a write packet operation
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C
+ * bus. This is the non-blocking equivalent of \ref i2c_master_write_packet_wait.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_master_write_packet_job(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with another job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Make sure we send STOP at end*/
+ module->send_stop = true;
+ module->send_nack = true;
+ /* Start write operation */
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \brief Initiates a write packet operation without sending a STOP condition when done
+ *
+ * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus
+ * without sending a stop condition, thus retaining ownership of the bus when
+ * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or
+ * \ref i2c_master_write_packet_wait "write" with stop condition or sending
+ * a stop with the \ref i2c_master_send_stop function must be performed.
+ *
+ * This is the non-blocking equivalent of \ref i2c_master_write_packet_wait_no_stop.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet job.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another
+ */
+enum status_code i2c_master_write_packet_job_no_stop(
+ struct i2c_master_module *const module,
+ struct i2c_master_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy with another job. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Do not send stop condition when done */
+ module->send_stop = false;
+ module->send_nack = true;
+ /* Start write operation */
+ return _i2c_master_write_packet(module, packet);
+}
+
+/**
+ * \internal
+ * Interrupt handler for I<SUP>2</SUP>C master.
+ *
+ * \param[in] instance SERCOM instance that triggered the interrupt
+ */
+void _i2c_master_interrupt_handler(
+ uint8_t instance)
+{
+ /* Get software module for callback handling */
+ struct i2c_master_module *module =
+ (struct i2c_master_module*)_sercom_instances[instance];
+
+ Assert(module);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Combine callback registered and enabled masks */
+ uint8_t callback_mask = module->enabled_callback &
+ module->registered_callback;
+
+ /* Check if the module should respond to address ack */
+ if ((module->buffer_length <= 0) && (module->buffer_remaining > 0)) {
+ /* Call function for address response */
+ _i2c_master_async_address_response(module);
+
+ /* Check if buffer write is done */
+ } else if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) &&
+ (module->status == STATUS_BUSY) &&
+ (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg =
+ SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+
+ module->buffer_length = 0;
+ module->status = STATUS_OK;
+
+ if (module->send_stop) {
+ /* Send stop condition */
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3);
+ } else {
+ /* Clear write interrupt flag */
+ i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_MB;
+ }
+ if (callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE)) {
+ module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module);
+ }
+
+ /* Continue buffer write/read */
+ } else if ((module->buffer_length > 0) && (module->buffer_remaining > 0)){
+ /* Check that bus ownership is not lost */
+ if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) {
+ module->status = STATUS_ERR_PACKET_COLLISION;
+ } else if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_master_write(module);
+ } else {
+ _i2c_master_read(module);
+ }
+ }
+
+ /* Check if read buffer transfer is complete */
+ if ((module->buffer_length > 0) && (module->buffer_remaining <= 0) &&
+ (module->status == STATUS_BUSY) &&
+ (module->transfer_direction == I2C_TRANSFER_READ)) {
+
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg =
+ SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB;
+ module->buffer_length = 0;
+ module->status = STATUS_OK;
+
+ /* Call appropriate callback if enabled and registered */
+ if ((callback_mask & (1 << I2C_MASTER_CALLBACK_READ_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_READ)) {
+ module->callbacks[I2C_MASTER_CALLBACK_READ_COMPLETE](module);
+ } else if ((callback_mask & (1 << I2C_MASTER_CALLBACK_WRITE_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ module->callbacks[I2C_MASTER_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+
+ /* Check for error */
+ if ((module->status != STATUS_BUSY) && (module->status != STATUS_OK)) {
+ /* Stop packet operation */
+ i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB |
+ SERCOM_I2CM_INTENCLR_SB;
+
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ /* Send nack and stop command unless arbitration is lost */
+ if ((module->status != STATUS_ERR_PACKET_COLLISION) &&
+ module->send_stop) {
+ _i2c_master_wait_for_sync(module);
+ i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT |
+ SERCOM_I2CM_CTRLB_CMD(3);
+ }
+
+ /* Call error callback if enabled and registered */
+ if (callback_mask & (1 << I2C_MASTER_CALLBACK_ERROR)) {
+ module->callbacks[I2C_MASTER_CALLBACK_ERROR](module);
+ }
+ }
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave.c
new file mode 100644
index 000000000..c403479a3
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave.c
@@ -0,0 +1,693 @@
+/**
+ * \file
+ *
+ * \brief SAM D20 I2C Slave Driver
+ *
+ * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_slave.h"
+#if I2C_SLAVE_CALLBACK_MODE == true
+# include "i2c_slave_interrupt.h"
+#endif
+
+/**
+ * \internal Sets configuration to module
+ *
+ * \param[out] module Pointer to software module structure
+ * \param[in] config Configuration structure with configurations to set
+ *
+ * \return Status of setting configuration.
+ * \retval STATUS_OK Module was configured correctly
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ */
+static enum status_code _i2c_slave_set_config(
+ struct i2c_slave_module *const module,
+ const struct i2c_slave_config *const config)
+{
+ uint32_t tmp_ctrla;
+
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(config);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ Sercom *const sercom_hw = module->hw;
+
+ module->buffer_timeout = config->buffer_timeout;
+
+ struct system_pinmux_config pin_conf;
+ system_pinmux_get_config_defaults(&pin_conf);
+
+ uint32_t pad0 = config->pinmux_pad0;
+ uint32_t pad1 = config->pinmux_pad1;
+
+ /* SERCOM PAD0 - SDA */
+ if (pad0 == PINMUX_DEFAULT) {
+ pad0 = _sercom_get_default_pad(sercom_hw, 0);
+ }
+ pin_conf.mux_position = pad0 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad0 >> 16, &pin_conf);
+
+ /* SERCOM PAD1 - SCL */
+ if (pad1 == PINMUX_DEFAULT) {
+ pad1 = _sercom_get_default_pad(sercom_hw, 1);
+ }
+ pin_conf.mux_position = pad1 & 0xFFFF;
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK;
+ system_pinmux_pin_set_config(pad1 >> 16, &pin_conf);
+
+ /* Prepare config to write to register CTRLA */
+ if (config->run_in_standby || system_is_debugger_present()) {
+ tmp_ctrla = SERCOM_I2CS_CTRLA_RUNSTDBY;
+ } else {
+ tmp_ctrla = 0;
+ }
+
+ tmp_ctrla |= config->sda_hold_time |
+ (config->scl_low_timeout << SERCOM_I2CS_CTRLA_LOWTOUT_Pos);
+
+ i2c_hw->CTRLA.reg |= tmp_ctrla;
+
+ /* Set CTRLB configuration */
+ i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_SMEN | config->address_mode;
+
+ i2c_hw->ADDR.reg = config->address << SERCOM_I2CS_ADDR_ADDR_Pos |
+ config->address_mask << SERCOM_I2CS_ADDR_ADDRMASK_Pos |
+ config->enable_general_call_address << SERCOM_I2CS_ADDR_GENCEN_Pos;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initializes the requested I<SUP>2</SUP>C hardware module
+ *
+ * Initializes the SERCOM I<SUP>2</SUP>C slave device requested and sets the provided
+ * software module struct. Run this function before any further use of
+ * the driver.
+ *
+ * \param[out] module Pointer to software module struct
+ * \param[in] hw Pointer to the hardware instance
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return Status of initialization.
+ * \retval STATUS_OK Module initiated correctly
+ * \retval STATUS_ERR_DENIED If module is enabled
+ * \retval STATUS_BUSY If module is busy resetting
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than
+ * previously set
+ */
+enum status_code i2c_slave_init(
+ struct i2c_slave_module *const module,
+ Sercom *const hw,
+ const struct i2c_slave_config *const config)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(hw);
+ Assert(config);
+
+ /* Initialize software module */
+ module->hw = hw;
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Check if module is enabled. */
+ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_ENABLE) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if reset is in progress. */
+ if (i2c_hw->CTRLA.reg & SERCOM_I2CS_CTRLA_SWRST) {
+ return STATUS_BUSY;
+ }
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+ uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+
+ /* Turn on module in PM */
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+
+ /* Set up the GCLK for the module */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->generator_source;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->generator_source, false);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Get sercom instance index. */
+ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
+
+ /* Save software module in interrupt handler. */
+ _sercom_set_handler(instance_index, _i2c_slave_interrupt_handler);
+
+ /* Save software module. */
+ _sercom_instances[instance_index] = module;
+
+ /* Initialize values in module. */
+ module->registered_callback = 0;
+ module->enabled_callback = 0;
+ module->buffer_length = 0;
+ module->nack_on_address = config->enable_nack_on_address;
+#endif
+
+ /* Set SERCOM module to operate in I2C slave mode. */
+ i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_MODE_I2C_SLAVE;
+
+ /* Set config and return status. */
+ return _i2c_slave_set_config(module, config);
+}
+
+/**
+ * \brief Resets the hardware module
+ *
+ * This will reset the module to hardware defaults.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_slave_reset(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Reset module instance. */
+ module->registered_callback = 0;
+ module->enabled_callback = 0;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+ module->buffer = NULL;
+#endif
+
+ /* Disable module */
+ i2c_slave_disable(module);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Clear all pending interrupts. */
+ system_interrupt_enter_critical_section();
+ system_interrupt_clear_pending(_sercom_get_interrupt_vector(module->hw));
+ system_interrupt_leave_critical_section();
+#endif
+
+ /* Wait for sync. */
+ _i2c_slave_wait_for_sync(module);
+
+ /* Reset module. */
+ i2c_hw->CTRLA.reg = SERCOM_I2CS_CTRLA_SWRST;
+}
+
+/**
+ * \internal Waits for answer on bus
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Status of bus.
+ * \retval STATUS_OK If given response from slave device
+ * \retval STATUS_ERR_TIMEOUT If no response was given within specified timeout
+ * period
+ */
+static enum status_code _i2c_slave_wait_for_bus(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cm *const i2c_module = &(module->hw->I2CM);
+
+ /* Wait for reply. */
+ uint16_t timeout_counter = 0;
+ while ((!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY)) &&
+ (!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC)) &&
+ (!(i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH))) {
+
+ /* Check timeout condition. */
+ if (++timeout_counter >= module->buffer_timeout) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Writes a packet to the master
+ *
+ * Writes a packet to the master. This will wait for the master to issue
+ * a request.
+ *
+ * \param[in] module Pointer to software module structure
+ * \param[in] packet Packet to write to master
+ *
+ * \return Status of packet write.
+ * \retval STATUS_OK Packet was written successfully
+ * \retval STATUS_ERR_DENIED Start condition not received, another
+ * interrupt flag is set
+ * \retval STATUS_ERR_IO There was an error in the previous transfer
+ * \retval STATUS_ERR_BAD_FORMAT Master wants to write data
+ * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) was provided
+ * \retval STATUS_ERR_BUSY The I<SUP>2</SUP>C module is busy with a job
+ * \retval STATUS_ERR_ERR_OVERFLOW Master NACKed before entire packet was
+ * transferred
+ * \retval STATUS_ERR_TIMEOUT No response was given within the timeout
+ * period
+ */
+enum status_code i2c_slave_write_packet_wait(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ uint16_t length = packet->data_length;
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Check if the module is busy with a job or AMATCH is enabled */
+ if (module->buffer_remaining > 0 ||
+ (i2c_hw->INTENSET.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ enum status_code status;
+ /* Wait for master to send address packet */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if there was an error in last transfer */
+ if (i2c_hw->STATUS.reg & (SERCOM_I2CS_STATUS_BUSERR |
+ SERCOM_I2CS_STATUS_COLL | SERCOM_I2CS_STATUS_LOWTOUT)) {
+ return STATUS_ERR_IO;
+ }
+
+ /* Check direction */
+ if (!(i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR)) {
+ /* Write request from master, send NACK and return, workaround 13574*/
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ _i2c_slave_set_ctrlb_cmd3(module);
+ return STATUS_ERR_BAD_FORMAT;
+ }
+
+ /* Read request from master, ACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+ _i2c_slave_set_ctrlb_cmd3(module);
+
+ uint16_t i = 0;
+
+ /* Wait for data interrupt */
+ status = _i2c_slave_wait_for_bus(module);
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ while (length--) {
+ /* Write data */
+ _i2c_slave_wait_for_sync(module);
+ i2c_hw->DATA.reg = packet->data[i++];
+
+ /* Wait for response from master */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_RXNACK &&
+ length !=0) {
+ /* NACK from master, abort */
+ /* Release line */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x02);
+
+ return STATUS_ERR_OVERFLOW;
+ /* Workaround: PIF will probably not be set, ignore */
+ }
+ /* ACK from master, continue writing */
+ }
+
+ /* Release line */
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x02);
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Reads a packet from the master
+ *
+ * Reads a packet from the master. This will wait for the master to issue a
+ * request.
+ *
+ * \param[in] module Pointer to software module structure
+ * \param[out] packet Packet to read from master
+ *
+ * \return Status of packet read.
+ * \retval STATUS_OK Packet was read successfully
+ * \retval STATUS_ABORTED Master sent stop condition or repeated
+ * start before specified length of bytes
+ * was received
+ * \retval STATUS_ERR_IO There was an error in the previous transfer
+ * \retval STATUS_ERR_DENIED Start condition not received, another
+ * interrupt flag is set
+ * \retval STATUS_ERR_INVALID_ARG Invalid argument(s) was provided
+ * \retval STATUS_ERR_BUSY The I<SUP>2</SUP>C module is busy with a job
+ * \retval STATUS_ERR_BAD_FORMAT Master wants to read data
+ * \retval STATUS_ERR_ERR_OVERFLOW Last byte received overflows buffer
+ */
+enum status_code i2c_slave_read_packet_wait(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ uint16_t length = packet->data_length;
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Check if the module is busy with a job or AMATCH is enabled */
+ if (module->buffer_remaining > 0 ||
+ (i2c_hw->INTENSET.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ enum status_code status;
+
+ /* Wait for master to send address packet */
+ status = _i2c_slave_wait_for_bus(module);
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if there was an error in the last transfer */
+ if (i2c_hw->STATUS.reg & (SERCOM_I2CS_STATUS_BUSERR |
+ SERCOM_I2CS_STATUS_COLL | SERCOM_I2CS_STATUS_LOWTOUT)) {
+ return STATUS_ERR_IO;
+ }
+ /* Check direction */
+ if ((i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR)) {
+ /* Read request from master, send NACK and return, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ _i2c_slave_set_ctrlb_cmd3(module);
+ return STATUS_ERR_BAD_FORMAT;
+ }
+
+ /* Write request from master, ACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+ _i2c_slave_set_ctrlb_cmd3(module);
+
+ uint16_t i = 0;
+ while (length--) {
+
+ /* Wait for next byte or stop condition */
+ status = _i2c_slave_wait_for_bus(module);
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return status;
+ }
+
+ if ((i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) ||
+ i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ /* Master sent stop condition, or repeated start, read done */
+ /* Clear stop flag */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ return STATUS_ABORTED;
+ }
+
+ /* Read data */
+ _i2c_slave_wait_for_sync(module);
+ packet->data[i++] = i2c_hw->DATA.reg;
+
+ }
+
+ /* Packet read done, wait for packet to NACK, Stop or repeated start */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY) {
+ /* Buffer is full, send NACK */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+ }
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) {
+ /* Clear stop flag */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Waits for a start condition on the bus
+ *
+ * \note This function is only available for 7-bit slave addressing.
+ *
+ * Waits for the master to issue a start condition on the bus.
+ * \note This function does not check for errors in the last transfer,
+ * this will be discovered when reading or writing.
+ *
+ * \param[in] module Pointer to software module structure
+ *
+ * \return Direction of the current transfer, when in slave mode.
+ * \retval I2C_SLAVE_DIRECTION_NONE No request from master within timeout
+ * period
+ * \retval I2C_SLAVE_DIRECTION_READ Write request from master
+ * \retval I2C_SLAVE_DIRECTION_WRITE Read request from master
+ */
+enum i2c_slave_direction i2c_slave_get_direction_wait(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ enum status_code status;
+
+ /* Wait for address interrupt */
+ status = _i2c_slave_wait_for_bus(module);
+
+ if (status != STATUS_OK) {
+ /* Timeout, return */
+ return I2C_SLAVE_DIRECTION_NONE;
+ }
+
+ if (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH)) {
+ /* Not address interrupt, something is wrong */
+ return I2C_SLAVE_DIRECTION_NONE;
+ }
+
+ /* Check direction */
+ if ((i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR)) {
+ /* Read request from master */
+ return I2C_SLAVE_DIRECTION_WRITE;
+ } else {
+ /* Write request from master */
+ return I2C_SLAVE_DIRECTION_READ;
+ }
+}
+
+/**
+ * \brief Retrieves the current module status
+ *
+ * Checks the status of the module and returns it as a bitmask of status
+ * flags.
+ *
+ * \param[in] module Pointer to the I<SUP>2</SUP>C slave software device struct
+ *
+ * \return Bitmask of status flags.
+ *
+ * \retval I2C_SLAVE_STATUS_ADDRESS_MATCH A valid address has been received
+ * \retval I2C_SLAVE_STATUS_DATA_READY A I<SUP>2</SUP>C slave byte transmission is
+ * successfully completed
+ * \retval I2C_SLAVE_STATUS_STOP_RECEIVED A stop condition is detected for a
+ * transaction being processed
+ * \retval I2C_SLAVE_STATUS_CLOCK_HOLD The slave is holding the SCL line
+ * low
+ * \retval I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT An SCL low time-out has occurred
+ * \retval I2C_SLAVE_STATUS_REPEATED_START Indicates a repeated start, only
+ * valid if \ref
+ * I2C_SLAVE_STATUS_ADDRESS_MATCH is
+ * set
+ * \retval I2C_SLAVE_STATUS_RECEIVED_NACK The last data packet sent was not
+ * acknowledged
+ * \retval I2C_SLAVE_STATUS_COLLISION The I<SUP>2</SUP>C slave was not able to
+ * transmit a high data or NACK bit
+ * \retval I2C_SLAVE_STATUS_BUS_ERROR An illegal bus condition has
+ * occurred on the bus
+ */
+uint32_t i2c_slave_get_status(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ uint8_t intflags = i2c_hw->INTFLAG.reg;
+ uint8_t status = i2c_hw->STATUS.reg;
+ uint32_t status_flags = 0;
+
+ /* Check Address Match flag */
+ if (intflags & SERCOM_I2CS_INTFLAG_AMATCH) {
+ status_flags |= I2C_SLAVE_STATUS_ADDRESS_MATCH;
+ }
+ /* Check Data Ready flag */
+ if (intflags & SERCOM_I2CS_INTFLAG_DRDY) {
+ status_flags |= I2C_SLAVE_STATUS_DATA_READY;
+ }
+ /* Check Stop flag */
+ if (intflags & SERCOM_I2CS_INTFLAG_PREC) {
+ status_flags |= I2C_SLAVE_STATUS_STOP_RECEIVED;
+ }
+ /* Check Clock Hold */
+ if (status & SERCOM_I2CS_STATUS_CLKHOLD) {
+ status_flags |= I2C_SLAVE_STATUS_CLOCK_HOLD;
+ }
+ /* Check SCL Low Timeout */
+ if (status & SERCOM_I2CS_STATUS_LOWTOUT) {
+ status_flags |= I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT;
+ }
+ /* Check Repeated Start */
+ if (status & SERCOM_I2CS_STATUS_SR) {
+ status_flags |= I2C_SLAVE_STATUS_REPEATED_START;
+ }
+ /* Check Received Not Acknowledge */
+ if (status & SERCOM_I2CS_STATUS_RXNACK) {
+ status_flags |= I2C_SLAVE_STATUS_RECEIVED_NACK;
+ }
+ /* Check Transmit Collision */
+ if (status & SERCOM_I2CS_STATUS_COLL) {
+ status_flags |= I2C_SLAVE_STATUS_COLLISION;
+ }
+ /* Check Bus Error */
+ if (status & SERCOM_I2CS_STATUS_BUSERR) {
+ status_flags |= I2C_SLAVE_STATUS_BUS_ERROR;
+ }
+
+ return status_flags;
+}
+
+/**
+ * \brief Clears a module status flag
+ *
+ * Clears the given status flag of the module.
+ *
+ * \note Not all status flags can be cleared.
+ *
+ * \param[in] module Pointer to the I<SUP>2</SUP>C software device struct
+ * \param[in] status_flags Bit mask of status flags to clear
+ *
+ */
+void i2c_slave_clear_status(
+ struct i2c_slave_module *const module,
+ uint32_t status_flags)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Clear Address Match flag */
+ if (status_flags & I2C_SLAVE_STATUS_ADDRESS_MATCH) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+ /* Clear Data Ready flag */
+ if (status_flags & I2C_SLAVE_STATUS_DATA_READY) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_DRDY;
+ }
+ /* Clear Stop flag */
+ if (status_flags & I2C_SLAVE_STATUS_STOP_RECEIVED) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ }
+ /* Clear SCL Low Timeout */
+ if (status_flags & I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT) {
+ i2c_hw->STATUS.reg = SERCOM_I2CS_STATUS_LOWTOUT;
+ }
+ /* Clear Transmit Collision */
+ if (status_flags & I2C_SLAVE_STATUS_COLLISION) {
+ i2c_hw->STATUS.reg = SERCOM_I2CS_STATUS_COLL;
+ }
+ /* Clear Bus Error */
+ if (status_flags & I2C_SLAVE_STATUS_BUS_ERROR) {
+ i2c_hw->STATUS.reg = SERCOM_I2CS_STATUS_BUSERR;
+ }
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave_interrupt.c
new file mode 100644
index 000000000..29d222bd2
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_samd20/i2c_slave_interrupt.c
@@ -0,0 +1,434 @@
+/**
+ * \file
+ *
+ * \brief SAM D20 I2C Slave Interrupt Driver
+ *
+ * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "i2c_slave_interrupt.h"
+
+/**
+ * \brief Enables sending of NACK on address match
+ *
+ * Enables sending of NACK on address match, thus discarding
+ * any incoming transaction.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_slave_enable_nack_on_address(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+
+ module->nack_on_address = true;
+}
+
+/**
+ * \brief Disables sending NACK on address match
+ *
+ * Disables sending of NACK on address match, thus
+ * acknowledging incoming transactions.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+void i2c_slave_disable_nack_on_address(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check arguments. */
+ Assert(module);
+
+ module->nack_on_address = false;
+}
+
+/**
+ * \internal
+ * Reads next data. Used by interrupt handler to get next data byte from master.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_slave_read(
+ struct i2c_slave_module *const module)
+{
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Read byte from master and put in buffer. */
+ *(module->buffer++) = i2c_hw->DATA.reg;
+
+ /*Decrement remaining buffer length */
+ module->buffer_remaining--;
+}
+
+/**
+ * \internal
+ * Writes next data. Used by interrupt handler to send next data byte to master.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static void _i2c_slave_write(
+ struct i2c_slave_module *const module)
+{
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Write byte from buffer to master */
+ i2c_hw->DATA.reg = *(module->buffer++);
+
+ /*Decrement remaining buffer length */
+ module->buffer_remaining--;
+}
+
+/**
+ * \brief Registers callback for the specified callback type
+ *
+ * Associates the given callback function with the
+ * specified callback type. To enable the callback, the
+ * \ref i2c_slave_enable_callback function must be used.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback Pointer to the function desired for the
+ * specified callback
+ * \param[in] callback_type Callback type to register
+ */
+void i2c_slave_register_callback(
+ struct i2c_slave_module *const module,
+ i2c_slave_callback_t callback,
+ enum i2c_slave_callback callback_type)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+ Assert(callback);
+
+ /* Register callback. */
+ module->callbacks[callback_type] = callback;
+
+ /* Set corresponding bit to set callback as initiated. */
+ module->registered_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters callback for the specified callback type
+ *
+ * Removes the currently registered callback for the given callback
+ * type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to unregister
+ */
+void i2c_slave_unregister_callback(
+ struct i2c_slave_module *const module,
+ enum i2c_slave_callback callback_type)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Register callback. */
+ module->callbacks[callback_type] = NULL;
+
+ /* Set corresponding bit to set callback as initiated. */
+ module->registered_callback &= ~(1 << callback_type);
+}
+
+/**
+ * \brief Initiates a reads packet operation
+ *
+ * Reads a data packet from the master. A write request must be initiated by
+ * the master before the packet can be read.
+ *
+ * The \ref I2C_SLAVE_CALLBACK_WRITE_REQUEST callback can be used to call this
+ * function.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting asynchronously reading I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If reading was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_slave_read_packet_job(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy doing async operation. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Save packet to software module. */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->buffer_length = packet->data_length;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ i2c_hw->INTENSET.reg = SERCOM_I2CS_INTFLAG_AMATCH |
+ SERCOM_I2CS_INTFLAG_DRDY | SERCOM_I2CS_INTFLAG_PREC;
+
+ /* Read will begin when master initiates the transfer */
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initiates a write packet operation
+ *
+ * Writes a data packet to the master. A read request must be initiated by
+ * the master before the packet can be written.
+ *
+ * The \ref I2C_SLAVE_CALLBACK_READ_REQUEST callback can be used to call this
+ * function.
+ *
+ * \param[in,out] module Pointer to software module struct
+ * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer
+ *
+ * \return Status of starting writing I<SUP>2</SUP>C packet.
+ * \retval STATUS_OK If writing was started successfully
+ * \retval STATUS_BUSY If module is currently busy with another transfer
+ */
+enum status_code i2c_slave_write_packet_job(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+ Assert(packet);
+
+ /* Check if the I2C module is busy doing async operation. */
+ if (module->buffer_remaining > 0) {
+ return STATUS_BUSY;
+ }
+
+ /* Save packet to software module. */
+ module->buffer = packet->data;
+ module->buffer_remaining = packet->data_length;
+ module->buffer_length = packet->data_length;
+ module->status = STATUS_BUSY;
+
+ /* Enable interrupts */
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ i2c_hw->INTENSET.reg = SERCOM_I2CS_INTFLAG_AMATCH |
+ SERCOM_I2CS_INTFLAG_DRDY | SERCOM_I2CS_INTFLAG_PREC;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal Interrupt handler for I<SUP>2</SUP>C slave
+ *
+ * \param[in] instance Sercom instance that triggered the interrupt
+ */
+void _i2c_slave_interrupt_handler(
+ uint8_t instance)
+{
+ /* Get software module for callback handling. */
+ struct i2c_slave_module *module =
+ (struct i2c_slave_module*)_sercom_instances[instance];
+
+ Assert(module);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Combine callback registered and enabled masks. */
+ uint8_t callback_mask =
+ module->enabled_callback & module->registered_callback;
+
+
+ if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) {
+ /* Address match */
+ /* Check if last transfer is done - repeated start */
+ if (module->buffer_length != module->buffer_remaining &&
+ module->transfer_direction == I2C_TRANSFER_WRITE) {
+
+ module->status = STATUS_OK;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE))) {
+ module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
+ }
+ } else if (module->buffer_length != module->buffer_remaining &&
+ module->transfer_direction == I2C_TRANSFER_READ) {
+ module->status = STATUS_OK;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_COMPLETE))) {
+ module->callbacks[I2C_SLAVE_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+
+ if (i2c_hw->STATUS.reg & (SERCOM_I2CS_STATUS_BUSERR |
+ SERCOM_I2CS_STATUS_COLL | SERCOM_I2CS_STATUS_LOWTOUT)) {
+ /* An error occurred in last packet transfer */
+ module->status = STATUS_ERR_IO;
+
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_ERROR_LAST_TRANSFER))) {
+ module->callbacks[I2C_SLAVE_CALLBACK_ERROR_LAST_TRANSFER](module);
+ }
+ }
+ if (module->nack_on_address) {
+ /* NACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ } else if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR) {
+ /* Set transfer direction in module instance */
+ module->transfer_direction = I2C_TRANSFER_READ;
+
+ /* Read request from master */
+ if (callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_REQUEST)) {
+ module->callbacks[I2C_SLAVE_CALLBACK_READ_REQUEST](module);
+ }
+
+ if (module->buffer_length == 0) {
+ /* Data buffer not set up, NACK address, workaround 13574*/
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ } else {
+ /* ACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+ }
+ } else {
+ /* Set transfer direction in dev inst */
+ module->transfer_direction = I2C_TRANSFER_WRITE;
+
+ /* Write request from master */
+ if (callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_REQUEST)) {
+ module->callbacks[I2C_SLAVE_CALLBACK_WRITE_REQUEST](module);
+ }
+
+ if (module->buffer_length == 0) {
+ /* Data buffer not set up, NACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ } else {
+ /* ACK address, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+ }
+ }
+
+ /* ACK or NACK address, Workaround 13574 */
+ _i2c_slave_set_ctrlb_cmd3(module);
+
+ /* ACK next incoming packet, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, true);
+
+ } else if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) {
+ /* Stop condition on bus - current transfer done */
+
+ /* Clear Stop interrupt */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+
+ /* Disable interrupts */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_PREC | SERCOM_I2CS_INTFLAG_DRDY;
+
+ if (!((module->enabled_callback & (1 << I2C_SLAVE_CALLBACK_READ_REQUEST))
+ || (module->enabled_callback == (1 << I2C_SLAVE_CALLBACK_WRITE_REQUEST)))) {
+ /* Disable address match if read/write request is not enabled */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+
+ if (!(module->status == STATUS_ERR_OVERFLOW || module->status == STATUS_ERR_IO)) {
+ module->status = STATUS_OK;
+ module->buffer_length = 0;
+ module->buffer_remaining = 0;
+
+ /* Call appropriate callback if enabled and registered */
+ if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_READ_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_WRITE)) {
+ /* Read from master complete */
+ module->callbacks[I2C_SLAVE_CALLBACK_READ_COMPLETE](module);
+ } else if ((callback_mask & (1 << I2C_SLAVE_CALLBACK_WRITE_COMPLETE))
+ && (module->transfer_direction == I2C_TRANSFER_READ)) {
+ /* Write to master complete */
+ module->callbacks[I2C_SLAVE_CALLBACK_WRITE_COMPLETE](module);
+ }
+ }
+ } else if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY) {
+ /* Check if buffer is full, or NACK from master */
+ if (module->buffer_remaining <= 0 ||
+ (module->transfer_direction == I2C_TRANSFER_READ &&
+ (module->buffer_length > module->buffer_remaining) &&
+ (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_RXNACK))) {
+
+ module->buffer_remaining = 0;
+ module->buffer_length = 0;
+
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ /* Buffer is full, send NACK, workaround 13574 */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+
+ /* Set status, new character in DATA register will overflow
+ * buffer */
+ module->status = STATUS_ERR_OVERFLOW;
+
+ if (callback_mask & (1 << I2C_SLAVE_CALLBACK_ERROR)) {
+ /* Read complete */
+ module->callbacks[I2C_SLAVE_CALLBACK_ERROR](module);
+ }
+ } else {
+ /* Release SCL and wait for new start condition */
+ _i2c_slave_set_ctrlb_ackact(module, false);
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2);
+
+ /* Transfer successful */
+ module->status = STATUS_OK;
+
+ /* Disable interrupts */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_DRDY;
+ }
+
+ /* Continue buffer write/read */
+ } else if (module->buffer_length > 0 && module->buffer_remaining > 0) {
+ /* Call function based on transfer direction */
+ if (module->transfer_direction == I2C_TRANSFER_WRITE) {
+ _i2c_slave_read(module);
+ } else {
+ _i2c_slave_write(module);
+ }
+ }
+ }
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave.h b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave.h
new file mode 100644
index 000000000..20eb78ec0
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave.h
@@ -0,0 +1,753 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Slave Driver
+ *
+ * Copyright (c) 2013-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef I2C_SLAVE_H_INCLUDED
+#define I2C_SLAVE_H_INCLUDED
+
+#include "i2c_common.h"
+#include <sercom.h>
+#include <pinmux.h>
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+# include <sercom_interrupt.h>
+#endif
+
+#ifndef PINMUX_DEFAULT
+# define PINMUX_DEFAULT 0
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_i2c_group
+ *
+ * @{
+ *
+ */
+
+/**
+ * \name I2C Slave Status Flags
+ *
+ * I<SUP>2</SUP>C slave status flags, returned by \ref i2c_slave_get_status() and cleared
+ * by \ref i2c_slave_clear_status().
+ * @{
+ */
+
+/** Address Match.
+ * \note Should only be cleared internally by driver.
+ */
+#define I2C_SLAVE_STATUS_ADDRESS_MATCH (1UL << 0)
+/** Data Ready. */
+#define I2C_SLAVE_STATUS_DATA_READY (1UL << 1)
+/** Stop Received. */
+#define I2C_SLAVE_STATUS_STOP_RECEIVED (1UL << 2)
+/** Clock Hold.
+ * \note Cannot be cleared, only valid when I2C_SLAVE_STATUS_ADDRESS_MATCH is
+ * set.
+ */
+#define I2C_SLAVE_STATUS_CLOCK_HOLD (1UL << 3)
+/** SCL Low Timeout. */
+#define I2C_SLAVE_STATUS_SCL_LOW_TIMEOUT (1UL << 4)
+/** Repeated Start.
+ * \note Cannot be cleared, only valid when I2C_SLAVE_STATUS_ADDRESS_MATCH is
+ * set.
+ */
+#define I2C_SLAVE_STATUS_REPEATED_START (1UL << 5)
+/** Received not acknowledge.
+ * \note Cannot be cleared.
+ */
+#define I2C_SLAVE_STATUS_RECEIVED_NACK (1UL << 6)
+/** Transmit Collision. */
+#define I2C_SLAVE_STATUS_COLLISION (1UL << 7)
+/** Bus error. */
+#define I2C_SLAVE_STATUS_BUS_ERROR (1UL << 8)
+
+/** @} */
+
+/**
+ * \brief I<SUP>2</SUP>C slave packet for read/write
+ *
+ * Structure to be used when transferring I<SUP>2</SUP>C slave packets.
+ */
+struct i2c_slave_packet {
+ /** Length of data array */
+ uint16_t data_length;
+ /** Data array containing all data to be transferred */
+ uint8_t *data;
+};
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /**
+ * \brief Callback types
+ *
+ * The available callback types for the I<SUP>2</SUP>C slave.
+ */
+enum i2c_slave_callback {
+ /** Callback for packet write complete */
+ I2C_SLAVE_CALLBACK_WRITE_COMPLETE,
+ /** Callback for packet read complete */
+ I2C_SLAVE_CALLBACK_READ_COMPLETE,
+ /**
+ * Callback for read request from master - can be used to
+ * issue a write
+ */
+ I2C_SLAVE_CALLBACK_READ_REQUEST,
+ /**
+ * Callback for write request from master - can be used to issue a read
+ */
+ I2C_SLAVE_CALLBACK_WRITE_REQUEST,
+ /** Callback for error */
+ I2C_SLAVE_CALLBACK_ERROR,
+ /**
+ * Callback for error in last transfer. Discovered on a new address
+ * interrupt.
+ */
+ I2C_SLAVE_CALLBACK_ERROR_LAST_TRANSFER,
+# if !defined(__DOXYGEN__)
+ /** Total number of callbacks */
+ _I2C_SLAVE_CALLBACK_N,
+# endif
+};
+
+# if !defined(__DOXYGEN__)
+/** Software module prototype */
+struct i2c_slave_module;
+
+/** Callback type */
+typedef void (*i2c_slave_callback_t)(
+ struct i2c_slave_module *const module);
+# endif
+#endif
+
+/**
+ * \brief Enum for the possible SDA hold times with respect to the negative
+ * edge of SCL
+ *
+ * Enum for the possible SDA hold times with respect to the negative edge
+ * of SCL.
+ */
+enum i2c_slave_sda_hold_time {
+ /** SDA hold time disabled */
+ I2C_SLAVE_SDA_HOLD_TIME_DISABLED =
+ ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((0) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))),
+ /** SDA hold time 50ns - 100ns */
+ I2C_SLAVE_SDA_HOLD_TIME_50NS_100NS =
+ ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((1) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))),
+ /** SDA hold time 300ns - 600ns */
+ I2C_SLAVE_SDA_HOLD_TIME_300NS_600NS =
+ ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((2) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))),
+ /** SDA hold time 400ns - 800ns */
+ I2C_SLAVE_SDA_HOLD_TIME_400NS_800NS =
+ ((SERCOM_I2CS_CTRLA_SDAHOLD_Msk & ((3) << SERCOM_I2CS_CTRLA_SDAHOLD_Pos))),
+};
+
+/**
+ * \brief Enum for the possible address modes
+ *
+ * Enum for the possible address modes.
+ */
+enum i2c_slave_address_mode {
+ /** Address match on address_mask used as a mask to address */
+ I2C_SLAVE_ADDRESS_MODE_MASK = SERCOM_I2CS_CTRLB_AMODE(0),
+ /** Address math on both address and address_mask */
+ I2C_SLAVE_ADDRESS_MODE_TWO_ADDRESSES = SERCOM_I2CS_CTRLB_AMODE(1),
+ /**
+ * Address match on range of addresses between and including address and
+ * address_mask
+ */
+ I2C_SLAVE_ADDRESS_MODE_RANGE = SERCOM_I2CS_CTRLB_AMODE(2),
+};
+
+/**
+ * \brief Enum for the direction of a request
+ *
+ * Enum for the direction of a request.
+ */
+enum i2c_slave_direction {
+ /** Read */
+ I2C_SLAVE_DIRECTION_READ,
+ /** Write */
+ I2C_SLAVE_DIRECTION_WRITE,
+ /** No direction */
+ I2C_SLAVE_DIRECTION_NONE,
+};
+
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+/**
+ * \brief Enum for the transfer speed
+ *
+ * Enum for the transfer speed.
+ */
+enum i2c_slave_transfer_speed {
+ /** Standard-mode (Sm) up to 100KHz and Fast-mode (Fm) up to 400KHz */
+ I2C_SLAVE_SPEED_STANDARD_AND_FAST = SERCOM_I2CS_CTRLA_SPEED(0),
+ /** Fast-mode Plus (Fm+) up to 1MHz */
+ I2C_SLAVE_SPEED_FAST_MODE_PLUS = SERCOM_I2CS_CTRLA_SPEED(1),
+ /** High-speed mode (Hs-mode) up to 3.4MHz */
+ I2C_SLAVE_SPEED_HIGH_SPEED = SERCOM_I2CS_CTRLA_SPEED(2),
+};
+#endif
+
+/**
+ * \brief SERCOM I<SUP>2</SUP>C slave driver software device instance structure.
+ *
+ * SERCOM I<SUP>2</SUP>C slave driver software instance structure, used to
+ * retain software state information of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved for module-internal use only.
+ */
+struct i2c_slave_module {
+#if !defined(__DOXYGEN__)
+ /** Hardware instance initialized for the struct */
+ Sercom *hw;
+ /** Module lock */
+ volatile bool locked;
+ /** Timeout value for polled functions */
+ uint16_t buffer_timeout;
+# ifdef FEATURE_I2C_10_BIT_ADDRESS
+ /** Using 10-bit addressing for the slave */
+ bool ten_bit_address;
+# endif
+# if I2C_SLAVE_CALLBACK_MODE == true
+ /** Nack on address match */
+ bool nack_on_address;
+ /** Pointers to callback functions */
+ volatile i2c_slave_callback_t callbacks[_I2C_SLAVE_CALLBACK_N];
+ /** Mask for registered callbacks */
+ volatile uint8_t registered_callback;
+ /** Mask for enabled callbacks */
+ volatile uint8_t enabled_callback;
+ /** The total number of bytes to transfer */
+ volatile uint16_t buffer_length;
+ /**
+ * Counter used for bytes left to send in write and to count number of
+ * obtained bytes in read
+ */
+ uint16_t buffer_remaining;
+ /** Data buffer for packet write and read */
+ volatile uint8_t *buffer;
+ /** Save direction of request from master. 1 = read, 0 = write. */
+ volatile enum i2c_transfer_direction transfer_direction;
+ /** Status for status read back in error callback */
+ volatile enum status_code status;
+# endif
+#endif
+};
+
+/**
+ * \brief Configuration structure for the I<SUP>2</SUP>C slave device
+ *
+ * This is the configuration structure for the I<SUP>2</SUP>C slave device. It is used
+ * as an argument for \ref i2c_slave_init to provide the desired
+ * configurations for the module. The structure should be initialized using the
+ * \ref i2c_slave_get_config_defaults.
+ */
+struct i2c_slave_config {
+ /** Set to enable the SCL low timeout */
+ bool enable_scl_low_timeout;
+ /** SDA hold time with respect to the negative edge of SCL */
+ enum i2c_slave_sda_hold_time sda_hold_time;
+ /** Timeout to wait for master in polled functions */
+ uint16_t buffer_timeout;
+ /** Addressing mode */
+ enum i2c_slave_address_mode address_mode;
+ /** Address or upper limit of address range */
+ uint16_t address;
+ /** Address mask, second address, or lower limit of address range */
+ uint16_t address_mask;
+#ifdef FEATURE_I2C_10_BIT_ADDRESS
+ /** Enable 10-bit addressing */
+ bool ten_bit_address;
+#endif
+ /**
+ * Enable general call address recognition (general call address
+ * is defined as 0000000 with direction bit 0).
+ */
+ bool enable_general_call_address;
+
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+ /** Transfer speed mode */
+ enum i2c_slave_transfer_speed transfer_speed;
+#endif
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /**
+ * Enable NACK on address match (this can be changed after initialization
+ * via the \ref i2c_slave_enable_nack_on_address and
+ * \ref i2c_slave_disable_nack_on_address functions).
+ */
+ bool enable_nack_on_address;
+#endif
+ /** GCLK generator to use as clock source */
+ enum gclk_generator generator_source;
+ /** Set to keep module active in sleep modes */
+ bool run_in_standby;
+ /** PAD0 (SDA) pinmux */
+ uint32_t pinmux_pad0;
+ /** PAD1 (SCL) pinmux */
+ uint32_t pinmux_pad1;
+ /** Set to enable SCL low time-out */
+ bool scl_low_timeout;
+#ifdef FEATURE_I2C_SCL_STRETCH_MODE
+ /** Set to enable SCL stretch only after ACK bit (required for high speed) */
+ bool scl_stretch_only_after_ack_bit;
+#endif
+#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT
+ /** Set to enable slave SCL low extend time-out */
+ bool slave_scl_low_extend_timeout;
+#endif
+};
+
+
+/**
+ * \name Lock/Unlock
+ * @{
+ */
+
+/**
+ * \brief Attempt to get lock on driver instance
+ *
+ * This function checks the instance's lock, which indicates whether or not it
+ * is currently in use, and sets the lock if it was not already set.
+ *
+ * The purpose of this is to enable exclusive access to driver instances, so
+ * that, e.g., transactions by different services will not interfere with each
+ * other.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline enum status_code i2c_slave_lock(
+ struct i2c_slave_module *const module)
+{
+ enum status_code status;
+
+ system_interrupt_enter_critical_section();
+
+ if (module->locked) {
+ status = STATUS_BUSY;
+ } else {
+ module->locked = true;
+ status = STATUS_OK;
+ }
+
+ system_interrupt_leave_critical_section();
+
+ return status;
+}
+
+/**
+ * \brief Unlock driver instance
+ *
+ * This function clears the instance lock, indicating that it is available for
+ * use.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline void i2c_slave_unlock(struct i2c_slave_module *const module)
+{
+ module->locked = false;
+}
+
+/** @} */
+
+/**
+ * \name Configuration and Initialization
+ * @{
+ */
+
+/**
+ * \brief Returns the synchronization status of the module
+ *
+ * Returns the synchronization status of the module.
+ *
+ * \param[out] module Pointer to software module structure
+ *
+ * \return Status of the synchronization.
+ * \retval true Module is busy synchronizing
+ * \retval false Module is not synchronizing
+ */
+static inline bool i2c_slave_is_syncing(
+ const struct i2c_slave_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+ /* Return sync status */
+#if defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1)
+ return (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_SYNCBUSY);
+#elif defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2)
+ return (i2c_hw->SYNCBUSY.reg & SERCOM_I2CS_SYNCBUSY_MASK);
+#else
+# error Unknown SERCOM SYNCBUSY scheme!
+#endif
+}
+
+#if !defined(__DOXYGEN__)
+/**
+ * \internal Wait for hardware module to sync
+ *
+ * \param[in] module Pointer to software module structure
+ */
+static void _i2c_slave_wait_for_sync(
+ const struct i2c_slave_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+
+ while (i2c_slave_is_syncing(module)) {
+ /* Wait for I<SUP>2</SUP>C module to sync */
+ }
+}
+#endif
+
+///@cond INTERNAL
+/**
+ * \internal Workaround for errata 13574
+ * Instead set ACK/NACK of CTRLB
+ *
+ * This errata exist in part revisions of SAM D20/D21/D09
+ * D10/D11/L21/L22/DA1/C20/C21/R30, but workaround can be works in all
+ * revision of those device. As this function operation
+ * should be use less cpu time as possible, so caller
+ * function can ignore to check revision number, and use
+ * this workaround in all revision of those device.
+ *
+ * \param[in,out] module Pointer to software module structure
+ * \param[in] send_ack true send ACK, false send NACK
+ */
+static inline void _i2c_slave_set_ctrlb_ackact(
+ struct i2c_slave_module *const module,
+ bool send_ack)
+{
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+#if (SAMD20 || SAMD21 || SAMD09 || SAMD10 || SAMD11 || SAML21 || SAMDA1 || \
+ SAML22 || SAMC20 || SAMC21 || SAMR30)
+ /* Workaround, Following two write are atomic */
+ system_interrupt_enter_critical_section();
+ i2c_hw->STATUS.reg = 0;
+
+ if (send_ack == true) {
+ i2c_hw->CTRLB.reg = 0;
+ }
+ else {
+ i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_ACKACT;
+ }
+ system_interrupt_leave_critical_section();
+#else
+ /* Normal operation */
+ if (send_ack == true) {
+ i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT;
+ }
+ else {
+ i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_ACKACT;
+ }
+#endif
+ return;
+}
+
+/**
+ * \internal Workaround for SAM0 errata 13574,
+ * instead Set CMD3 of CTRLB
+ *
+ * This errata exist in part revisions of SAM D20/D21/D09
+ * D10/D11/L21/DA1/C20/C21/R30, but workaround can be works in all
+ * revision of those device. As this function operation
+ * should be use less cpu time as possible, so caller
+ * function can ignore to check revision number, and use
+ * this workaround in all revision of those device.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static inline void _i2c_slave_set_ctrlb_cmd3(
+ struct i2c_slave_module *const module)
+{
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+#if (SAMD20 || SAMD21 || SAMD09 || SAMD10 || SAMD11 || SAML21 || SAML22 || \
+ SAMDA1 || SAMC20 || SAMC21 || SAMR30)
+ /* Workaround */
+ /*
+ * Below code instead i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_CMD(0x3);
+ * CMD=0x3 clears all interrupts, so to keep the result similar
+ * PREC is cleared if it was set
+ */
+ if (i2c_hw->INTFLAG.bit.PREC) {
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC;
+ }
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+#else
+ /* Normal operation */
+ i2c_hw->CTRLB.reg = SERCOM_I2CS_CTRLB_CMD(0x3);
+#endif
+ return;
+}
+///@endcond
+
+/**
+ * \brief Gets the I<SUP>2</SUP>C slave default configurations
+ *
+ * This will initialize the configuration structure to known default values.
+ *
+ * The default configuration is as follows:
+ * - Disable SCL low timeout
+ * - 300ns - 600ns SDA hold time
+ * - Buffer timeout = 65535
+ * - Address with mask
+ * - Address = 0
+ * - Address mask = 0 (one single address)
+ * - General call address disabled
+ * - Address nack disabled if the interrupt driver is used
+ * - GCLK generator 0
+ * - Do not run in standby
+ * - PINMUX_DEFAULT for SERCOM pads
+ *
+ * Those default configuration only available if the device supports it:
+ * - Not using 10-bit addressing
+ * - Standard-mode and Fast-mode transfer speed
+ * - SCL stretch disabled
+ * - Slave SCL low extend time-out disabled
+ *
+ * \param[out] config Pointer to configuration structure to be initialized
+ */
+static inline void i2c_slave_get_config_defaults(
+ struct i2c_slave_config *const config)
+{
+ /*Sanity check argument */
+ Assert(config);
+ config->enable_scl_low_timeout = false;
+ config->sda_hold_time = I2C_SLAVE_SDA_HOLD_TIME_300NS_600NS;
+ config->buffer_timeout = 65535;
+ config->address_mode = I2C_SLAVE_ADDRESS_MODE_MASK;
+ config->address = 0;
+ config->address_mask = 0;
+#ifdef FEATURE_I2C_10_BIT_ADDRESS
+ config->ten_bit_address = false;
+#endif
+ config->enable_general_call_address = false;
+#ifdef FEATURE_I2C_FAST_MODE_PLUS_AND_HIGH_SPEED
+ config->transfer_speed = I2C_SLAVE_SPEED_STANDARD_AND_FAST;
+#endif
+#if I2C_SLAVE_CALLBACK_MODE == true
+ config->enable_nack_on_address = false;
+#endif
+ config->generator_source = GCLK_GENERATOR_0;
+ config->run_in_standby = false;
+ config->pinmux_pad0 = PINMUX_DEFAULT;
+ config->pinmux_pad1 = PINMUX_DEFAULT;
+ config->scl_low_timeout = false;
+#ifdef FEATURE_I2C_SCL_STRETCH_MODE
+ config->scl_stretch_only_after_ack_bit = false;
+#endif
+#ifdef FEATURE_I2C_SCL_EXTEND_TIMEOUT
+ config->slave_scl_low_extend_timeout = false;
+#endif
+}
+
+enum status_code i2c_slave_init(struct i2c_slave_module *const module,
+ Sercom *const hw,
+ const struct i2c_slave_config *const config);
+
+/**
+ * \brief Enables the I<SUP>2</SUP>C module
+ *
+ * This will enable the requested I<SUP>2</SUP>C module.
+ *
+ * \param[in] module Pointer to the software module struct
+ */
+static inline void i2c_slave_enable(
+ const struct i2c_slave_module *const module)
+{
+ /* Sanity check of arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Enable global interrupt for module */
+ system_interrupt_enable(_sercom_get_interrupt_vector(module->hw));
+#endif
+
+ /* Wait for module to sync */
+ _i2c_slave_wait_for_sync(module);
+
+ /* Enable module */
+ i2c_hw->CTRLA.reg |= SERCOM_I2CS_CTRLA_ENABLE;
+}
+
+
+/**
+ * \brief Disables the I<SUP>2</SUP>C module
+ *
+ * This will disable the I<SUP>2</SUP>C module specified in the provided software module
+ * structure.
+ *
+ * \param[in] module Pointer to the software module struct
+ */
+static inline void i2c_slave_disable(
+ const struct i2c_slave_module *const module)
+{
+ /* Sanity check of arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+
+#if I2C_SLAVE_CALLBACK_MODE == true
+ /* Disable interrupts */
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTENSET_PREC |
+ SERCOM_I2CS_INTENSET_AMATCH | SERCOM_I2CS_INTENSET_DRDY;
+
+ /* Clear interrupt flags */
+ i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC | SERCOM_I2CS_INTFLAG_AMATCH |
+ SERCOM_I2CS_INTFLAG_DRDY;
+
+ /* Disable global interrupt for module */
+ system_interrupt_disable(_sercom_get_interrupt_vector(module->hw));
+#endif
+
+ /* Wait for module to sync */
+ _i2c_slave_wait_for_sync(module);
+
+ /* Disable module */
+ i2c_hw->CTRLA.reg &= ~SERCOM_I2CS_CTRLA_ENABLE;
+}
+
+void i2c_slave_reset(
+ struct i2c_slave_module *const module);
+
+/** @} */
+
+/**
+ * \name Read and Write
+ * @{
+ */
+
+enum status_code i2c_slave_write_packet_wait(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet);
+enum status_code i2c_slave_read_packet_wait(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet);
+enum i2c_slave_direction i2c_slave_get_direction_wait(
+ struct i2c_slave_module *const module);
+
+/** @} */
+
+/**
+ * \name Status Management
+ * @{
+ */
+uint32_t i2c_slave_get_status(
+ struct i2c_slave_module *const module);
+void i2c_slave_clear_status(
+ struct i2c_slave_module *const module,
+ uint32_t status_flags);
+/** @} */
+
+#ifdef FEATURE_I2C_DMA_SUPPORT
+/**
+ * \name SERCOM I2C slave with DMA Interfaces
+ * @{
+ */
+
+/**
+ * \brief Read SERCOM I<SUP>2</SUP>C interrupt status.
+ *
+ * Read I<SUP>2</SUP>C interrupt status for DMA transfer.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ */
+static inline uint8_t i2c_slave_dma_read_interrupt_status(struct i2c_slave_module *const module)
+{
+ return (uint8_t)module->hw->I2CS.INTFLAG.reg;
+}
+
+/**
+ * \brief Write SERCOM I<SUP>2</SUP>C interrupt status.
+ *
+ * Write I<SUP>2</SUP>C interrupt status for DMA transfer.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ * \param[in] flag Interrupt flag status
+ *
+ */
+static inline void i2c_slave_dma_write_interrupt_status(struct i2c_slave_module *const module,
+ uint8_t flag)
+{
+ module->hw->I2CS.INTFLAG.reg = flag;
+}
+
+/** @} */
+#endif
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I2C_SLAVE_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave_interrupt.h b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave_interrupt.h
new file mode 100644
index 000000000..cf1c4362c
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/i2c/i2c_slave_interrupt.h
@@ -0,0 +1,215 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM I2C Slave Interrupt Driver
+ *
+ * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef I2C_SLAVE_INTERRUPT_H_INCLUDED
+#define I2C_SLAVE_INTERRUPT_H_INCLUDED
+
+#include "i2c_slave.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_i2c_group
+ * @{
+ *
+ */
+
+/**
+ * \name Address Match Functionality
+ * @{
+ */
+
+void i2c_slave_enable_nack_on_address(
+ struct i2c_slave_module *const module);
+void i2c_slave_disable_nack_on_address(
+ struct i2c_slave_module *const module);
+
+/** @} */
+
+/**
+ * \name Callbacks
+ * @{
+ */
+#if !defined(__DOXYGEN__)
+void _i2c_slave_interrupt_handler(uint8_t instance);
+#endif
+
+void i2c_slave_register_callback(
+ struct i2c_slave_module *const module,
+ i2c_slave_callback_t callback,
+ enum i2c_slave_callback callback_type);
+
+void i2c_slave_unregister_callback(
+ struct i2c_slave_module *const module,
+ enum i2c_slave_callback callback_type);
+
+/**
+ * \brief Enables callback
+ *
+ * Enables the callback specified by the callback_type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to enable
+ */
+static inline void i2c_slave_enable_callback(
+ struct i2c_slave_module *const module,
+ enum i2c_slave_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Mark callback as enabled */
+ module->enabled_callback |= (1 << callback_type);
+
+ /* Enable address callback */
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ if (callback_type == I2C_SLAVE_CALLBACK_READ_REQUEST ||
+ callback_type == I2C_SLAVE_CALLBACK_WRITE_REQUEST) {
+ i2c_hw->INTENSET.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+}
+
+/**
+ * \brief Disables callback
+ *
+ * Disables the callback specified by the callback_type.
+ *
+ * \param[in,out] module Pointer to the software module struct
+ * \param[in] callback_type Callback type to disable
+ */
+static inline void i2c_slave_disable_callback(
+ struct i2c_slave_module *const module,
+ enum i2c_slave_callback callback_type)
+{
+ /* Sanity check */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Mark callback as disabled */
+ module->enabled_callback &= ~(1 << callback_type);
+ SercomI2cs *const i2c_hw = &(module->hw->I2CS);
+ if (callback_type == I2C_SLAVE_CALLBACK_READ_REQUEST ||
+ callback_type == I2C_SLAVE_CALLBACK_WRITE_REQUEST ||
+ module->status != STATUS_BUSY) {
+ i2c_hw->INTENCLR.reg = SERCOM_I2CS_INTFLAG_AMATCH;
+ }
+}
+
+/** @} */
+
+/**
+ * \name Read and Write, Interrupt-Driven
+ * @{
+ */
+
+
+enum status_code i2c_slave_read_packet_job(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet);
+
+enum status_code i2c_slave_write_packet_job(
+ struct i2c_slave_module *const module,
+ struct i2c_slave_packet *const packet);
+
+/**
+ * \brief Cancels any currently ongoing operation
+ *
+ * Terminates the running transfer operation.
+ *
+ * \param[in,out] module Pointer to software module structure
+ */
+static inline void i2c_slave_cancel_job(
+ struct i2c_slave_module *const module)
+{
+ /* Sanity check. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Set buffer to 0. */
+ module->buffer_remaining = 0;
+ module->buffer_length = 0;
+}
+
+/**
+ * \brief Gets status of ongoing job
+ *
+ * Will return the status of the ongoing job, or the error that occurred
+ * in the last transfer operation.
+ * The status will be cleared when starting a new job.
+ *
+ * \param[in,out] module Pointer to software module structure
+ *
+ * \return Status of job.
+ * \retval STATUS_OK No error has occurred
+ * \retval STATUS_BUSY Transfer is in progress
+ * \retval STATUS_ERR_IO A collision, timeout or bus error happened in
+ * the last transfer
+ * \retval STATUS_ERR_TIMEOUT A timeout occurred
+ * \retval STATUS_ERR_OVERFLOW Data from master overflows receive buffer
+ */
+static inline enum status_code i2c_slave_get_job_status(
+ struct i2c_slave_module *const module)
+{
+ /* Check sanity. */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Return current status code. */
+ return module->status;
+}
+
+/** @} */
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I2C_SLAVE_INTERRUPT_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/sercom.c b/atmel-samd/asf/sam0/drivers/sercom/sercom.c
new file mode 100644
index 000000000..637f3947f
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/sercom.c
@@ -0,0 +1,296 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include "sercom.h"
+
+#define SHIFT 32
+#define BAUD_INT_MAX 8192
+#define BAUD_FP_MAX 8
+
+#if !defined(__DOXYGEN__)
+/**
+ * \internal Configuration structure to save current gclk status.
+ */
+struct _sercom_conf {
+ /* Status of gclk generator initialization */
+ bool generator_is_set;
+ /* Sercom gclk generator used */
+ enum gclk_generator generator_source;
+};
+
+static struct _sercom_conf _sercom_config;
+
+
+/**
+ * \internal Calculate 64 bit division, ref can be found in
+ * http://en.wikipedia.org/wiki/Division_algorithm#Long_division
+ */
+static uint64_t long_division(uint64_t n, uint64_t d)
+{
+ int32_t i;
+ uint64_t q = 0, r = 0, bit_shift;
+ for (i = 63; i >= 0; i--) {
+ bit_shift = (uint64_t)1 << i;
+
+ r = r << 1;
+
+ if (n & bit_shift) {
+ r |= 0x01;
+ }
+
+ if (r >= d) {
+ r = r - d;
+ q |= bit_shift;
+ }
+ }
+
+ return q;
+}
+
+/**
+ * \internal Calculate synchronous baudrate value (SPI/UART)
+ */
+enum status_code _sercom_get_sync_baud_val(
+ const uint32_t baudrate,
+ const uint32_t external_clock,
+ uint16_t *const baudvalue)
+{
+ /* Baud value variable */
+ uint16_t baud_calculated = 0;
+ uint32_t clock_value = external_clock;
+
+
+ /* Check if baudrate is outside of valid range */
+ if (baudrate > (external_clock / 2)) {
+ /* Return with error code */
+ return STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ }
+
+ /* Calculate BAUD value from clock frequency and baudrate */
+ clock_value = external_clock / 2;
+ while (clock_value >= baudrate) {
+ clock_value = clock_value - baudrate;
+ baud_calculated++;
+ }
+ baud_calculated = baud_calculated - 1;
+
+ /* Check if BAUD value is more than 255, which is maximum
+ * for synchronous mode */
+ if (baud_calculated > 0xFF) {
+ /* Return with an error code */
+ return STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ } else {
+ *baudvalue = baud_calculated;
+ return STATUS_OK;
+ }
+}
+
+/**
+ * \internal Calculate asynchronous baudrate value (UART)
+*/
+enum status_code _sercom_get_async_baud_val(
+ const uint32_t baudrate,
+ const uint32_t peripheral_clock,
+ uint16_t *const baudval,
+ enum sercom_asynchronous_operation_mode mode,
+ enum sercom_asynchronous_sample_num sample_num)
+{
+ /* Temporary variables */
+ uint64_t ratio = 0;
+ uint64_t scale = 0;
+ uint64_t baud_calculated = 0;
+ uint8_t baud_fp;
+ uint32_t baud_int = 0;
+ uint64_t temp1, temp2;
+
+ /* Check if the baudrate is outside of valid range */
+ if ((baudrate * sample_num) > peripheral_clock) {
+ /* Return with error code */
+ return STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ }
+
+ if(mode == SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC) {
+ /* Calculate the BAUD value */
+ temp1 = ((sample_num * (uint64_t)baudrate) << SHIFT);
+ ratio = long_division(temp1, peripheral_clock);
+ scale = ((uint64_t)1 << SHIFT) - ratio;
+ baud_calculated = (65536 * scale) >> SHIFT;
+ } else if(mode == SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL) {
+ for(baud_fp = 0; baud_fp < BAUD_FP_MAX; baud_fp++) {
+ temp1 = BAUD_FP_MAX * (uint64_t)peripheral_clock;
+ temp2 = ((uint64_t)baudrate * sample_num);
+ baud_int = long_division(temp1, temp2);
+ baud_int -= baud_fp;
+ baud_int = baud_int / BAUD_FP_MAX;
+ if(baud_int < BAUD_INT_MAX) {
+ break;
+ }
+ }
+ if(baud_fp == BAUD_FP_MAX) {
+ return STATUS_ERR_BAUDRATE_UNAVAILABLE;
+ }
+ baud_calculated = baud_int | (baud_fp << 13);
+ }
+
+ *baudval = baud_calculated;
+ return STATUS_OK;
+}
+#endif
+
+/**
+ * \brief Set GCLK channel to generator.
+ *
+ * This will set the appropriate GCLK channel to the requested GCLK generator.
+ * This will set the generator for all SERCOM instances, and the user will thus
+ * only be able to set the same generator that has previously been set, if any.
+ *
+ * After the generator has been set the first time, the generator can be changed
+ * using the \c force_change flag.
+ *
+ * \param[in] generator_source The generator to use for SERCOM.
+ * \param[in] force_change Force change the generator.
+ *
+ * \return Status code indicating the GCLK generator change operation.
+ * \retval STATUS_OK If the generator update request was
+ * successful.
+ * \retval STATUS_ERR_ALREADY_INITIALIZED If a generator was already configured
+ * and the new configuration was not
+ * forced.
+ */
+enum status_code sercom_set_gclk_generator(
+ const enum gclk_generator generator_source,
+ const bool force_change)
+{
+ /* Check if valid option */
+ if (!_sercom_config.generator_is_set || force_change) {
+ /* Create and fill a GCLK configuration structure for the new config */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = generator_source;
+ system_gclk_chan_set_config(SERCOM_GCLK_ID, &gclk_chan_conf);
+ system_gclk_chan_enable(SERCOM_GCLK_ID);
+
+ /* Save config */
+ _sercom_config.generator_source = generator_source;
+ _sercom_config.generator_is_set = true;
+
+ return STATUS_OK;
+ } else if (generator_source == _sercom_config.generator_source) {
+ /* Return status OK if same config */
+ return STATUS_OK;
+ }
+
+ /* Return invalid config to already initialized GCLK */
+ return STATUS_ERR_ALREADY_INITIALIZED;
+}
+
+/** \internal
+ * Creates a switch statement case entry to convert a SERCOM instance and pad
+ * index to the default SERCOM pad MUX setting.
+ */
+#define _SERCOM_PAD_DEFAULTS_CASE(n, pad) \
+ case (uintptr_t)SERCOM##n: \
+ switch (pad) { \
+ case 0: \
+ return SERCOM##n##_PAD0_DEFAULT; \
+ case 1: \
+ return SERCOM##n##_PAD1_DEFAULT; \
+ case 2: \
+ return SERCOM##n##_PAD2_DEFAULT; \
+ case 3: \
+ return SERCOM##n##_PAD3_DEFAULT; \
+ } \
+ break;
+
+/**
+ * \internal Gets the default PAD pinout for a given SERCOM.
+ *
+ * Returns the pinmux settings for the given SERCOM and pad. This is used
+ * for default configuration of pins.
+ *
+ * \param[in] sercom_module Pointer to the SERCOM module
+ * \param[in] pad PAD to get default pinout for
+ *
+ * \returns The default pinmux for the given SERCOM instance and PAD
+ *
+ */
+uint32_t _sercom_get_default_pad(
+ Sercom *const sercom_module,
+ const uint8_t pad)
+{
+ switch ((uintptr_t)sercom_module) {
+ /* Auto-generate a lookup table for the default SERCOM pad defaults */
+ MREPEAT(SERCOM_INST_NUM, _SERCOM_PAD_DEFAULTS_CASE, pad)
+ }
+
+ Assert(false);
+ return 0;
+}
+
+/**
+ * \internal
+ * Find index of given instance.
+ *
+ * \param[in] sercom_instance Instance pointer.
+ *
+ * \return Index of given instance.
+ */
+uint8_t _sercom_get_sercom_inst_index(
+ Sercom *const sercom_instance)
+{
+ /* Save all available SERCOM instances for compare */
+ Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS;
+
+ /* Find index for sercom instance */
+ for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) {
+ if ((uintptr_t)sercom_instance == (uintptr_t)sercom_instances[i]) {
+ return i;
+ }
+ }
+
+ /* Invalid data given */
+ Assert(false);
+ return 0;
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/sercom.h b/atmel-samd/asf/sam0/drivers/sercom/sercom.h
new file mode 100644
index 000000000..60ce6f8ad
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/sercom.h
@@ -0,0 +1,118 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SERCOM_H_INCLUDED
+#define SERCOM_H_INCLUDED
+
+#include <compiler.h>
+#include <system.h>
+#include <clock.h>
+#include <system_interrupt.h>
+#include "sercom_pinout.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* SERCOM modules should share same slow GCLK channel ID */
+#define SERCOM_GCLK_ID SERCOM0_GCLK_ID_SLOW
+
+#if (0x1ff >= REV_SERCOM)
+# define FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1
+#elif (0x400 >= REV_SERCOM)
+# define FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2
+#else
+# error "Unknown SYNCBUSY scheme for this SERCOM revision"
+#endif
+
+/**
+ * \brief sercom asynchronous operation mode
+ *
+ * Select sercom asynchronous operation mode
+ */
+enum sercom_asynchronous_operation_mode {
+ SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC = 0,
+ SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL,
+};
+
+/**
+ * \brief sercom asynchronous samples per bit
+ *
+ * Select number of samples per bit
+ */
+enum sercom_asynchronous_sample_num {
+ SERCOM_ASYNC_SAMPLE_NUM_3 = 3,
+ SERCOM_ASYNC_SAMPLE_NUM_8 = 8,
+ SERCOM_ASYNC_SAMPLE_NUM_16 = 16,
+};
+
+enum status_code sercom_set_gclk_generator(
+ const enum gclk_generator generator_source,
+ const bool force_change);
+
+enum status_code _sercom_get_sync_baud_val(
+ const uint32_t baudrate,
+ const uint32_t external_clock,
+ uint16_t *const baudval);
+
+enum status_code _sercom_get_async_baud_val(
+ const uint32_t baudrate,
+ const uint32_t peripheral_clock,
+ uint16_t *const baudval,
+ enum sercom_asynchronous_operation_mode mode,
+ enum sercom_asynchronous_sample_num sample_num);
+
+uint32_t _sercom_get_default_pad(
+ Sercom *const sercom_module,
+ const uint8_t pad);
+
+uint8_t _sercom_get_sercom_inst_index(
+ Sercom *const sercom_instance);
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__SERCOM_H_INCLUDED
diff --git a/atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.c
new file mode 100644
index 000000000..b26d05b6e
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.c
@@ -0,0 +1,141 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include "sercom_interrupt.h"
+
+void *_sercom_instances[SERCOM_INST_NUM];
+
+/** Save status of initialized handlers */
+static bool _handler_table_initialized = false;
+
+/** Void pointers for saving device instance structures */
+static void (*_sercom_interrupt_handlers[SERCOM_INST_NUM])(const uint8_t instance);
+
+/**
+ * \internal
+ * Default interrupt handler.
+ *
+ * \param[in] instance SERCOM instance used.
+ */
+static void _sercom_default_handler(
+ const uint8_t instance)
+{
+ Assert(false);
+}
+
+/**
+ * \internal
+ * Saves the given callback handler.
+ *
+ * \param[in] instance Instance index.
+ * \param[in] interrupt_handler Pointer to instance callback handler.
+ */
+void _sercom_set_handler(
+ const uint8_t instance,
+ const sercom_handler_t interrupt_handler)
+{
+ /* Initialize handlers with default handler and device instances with 0 */
+ if (_handler_table_initialized == false) {
+ for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) {
+ _sercom_interrupt_handlers[i] = &_sercom_default_handler;
+ _sercom_instances[i] = NULL;
+ }
+
+ _handler_table_initialized = true;
+ }
+
+ /* Save interrupt handler */
+ _sercom_interrupt_handlers[instance] = interrupt_handler;
+}
+
+
+/** \internal
+ * Converts a given SERCOM index to its interrupt vector index.
+ */
+#define _SERCOM_INTERRUPT_VECT_NUM(n, unused) \
+ SYSTEM_INTERRUPT_MODULE_SERCOM##n,
+
+/** \internal
+ * Generates a SERCOM interrupt handler function for a given SERCOM index.
+ */
+#define _SERCOM_INTERRUPT_HANDLER(n, unused) \
+ void SERCOM##n##_Handler(void) \
+ { \
+ _sercom_interrupt_handlers[n](n); \
+ }
+
+/**
+ * \internal
+ * Returns the system interrupt vector.
+ *
+ * \param[in] sercom_instance Instance pointer
+ *
+ * \return Enum of system interrupt vector
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM0
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM1
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM2
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM3
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM4
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM5
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM6
+ * \retval SYSTEM_INTERRUPT_MODULE_SERCOM7
+ */
+enum system_interrupt_vector _sercom_get_interrupt_vector(
+ Sercom *const sercom_instance)
+{
+ const uint8_t sercom_int_vectors[SERCOM_INST_NUM] =
+ {
+ MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_VECT_NUM, ~)
+ };
+
+ /* Retrieve the index of the SERCOM being requested */
+ uint8_t instance_index = _sercom_get_sercom_inst_index(sercom_instance);
+
+ /* Get the vector number from the lookup table for the requested SERCOM */
+ return (enum system_interrupt_vector)sercom_int_vectors[instance_index];
+}
+
+/** Auto-generate a set of interrupt handlers for each SERCOM in the device */
+MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_HANDLER, ~)
diff --git a/atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.h b/atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.h
new file mode 100644
index 000000000..18945f518
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/sercom_interrupt.h
@@ -0,0 +1,72 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#ifndef SERCOM_INTERRUPT_H_INCLUDED
+#define SERCOM_INTERRUPT_H_INCLUDED
+
+#include "sercom.h"
+#include <system_interrupt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Look-up table for device instances */
+extern void *_sercom_instances[SERCOM_INST_NUM];
+
+typedef void (*sercom_handler_t)(uint8_t instance);
+
+enum system_interrupt_vector _sercom_get_interrupt_vector(
+ Sercom *const sercom_instance);
+
+void _sercom_set_handler(
+ const uint8_t instance,
+ const sercom_handler_t interrupt_handler);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SERCOM_INTERRUPT_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/sercom_pinout.h b/atmel-samd/asf/sam0/drivers/sercom/sercom_pinout.h
new file mode 100644
index 000000000..94ebc9cc0
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/sercom_pinout.h
@@ -0,0 +1,526 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM Module Pinout Definitions
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#ifndef SERCOM_PINOUT_H_INCLUDED
+#define SERCOM_PINOUT_H_INCLUDED
+
+#include <compiler.h>
+
+#if SAMR21E
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3
+
+ /* SERCOM3 */
+# if SAM_PART_IS_DEFINED(SAMR21E19A)
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1
+# else
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA27F_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA28F_SERCOM3_PAD1
+#endif
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3
+
+ /* SERCOM4 */
+# if SAM_PART_IS_DEFINED(SAMR21E19A)
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PB08D_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PB09D_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3
+# else
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PC19F_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PB31F_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PB30F_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PC18F_SERCOM4_PAD3
+# endif
+
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PB30D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PB31D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3
+
+#elif SAMR21G
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA12C_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA13C_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3
+
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PC19F_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PB31F_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PB30F_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PC18F_SERCOM4_PAD3
+
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3
+
+#elif (SAMD09)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA08D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA09D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA30C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA31C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA24C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA25C_SERCOM1_PAD3
+
+#elif (SAMD10DS) || (SAMD10DM) || (SAMD10DU) || (SAMD11DS) || (SAMD11DM) || (SAMD11DU)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA22C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA23C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA16D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA25D_SERCOM2_PAD3
+
+#elif (SAMD10C) || (SAMD11C)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA08D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA09D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA30C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA31C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA24C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA25C_SERCOM1_PAD3
+
+#elif SAM_PART_IS_DEFINED(SAMD21E15L) || SAM_PART_IS_DEFINED(SAMD21E16L)
+
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3
+
+#elif (SAML22N)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA10C_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA11C_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA20D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA21D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PB02C_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PB21C_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PB00C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PB01C_SERCOM3_PAD3
+
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PA12C_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PA13C_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PA14C_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PA15C_SERCOM4_PAD3
+
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PB30D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PB31D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PB22D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PB23D_SERCOM5_PAD3
+#elif (SAML22J)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA10C_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA11C_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA20D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA21D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PB02C_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PB13C_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PB00C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PB01C_SERCOM3_PAD3
+#elif (SAML22G)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA08C_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA09C_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA10C_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA11C_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA22D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA23D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA20D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA21D_SERCOM2_PAD3
+#elif (SAMC20E) || (SAMC21E)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3
+
+#elif (SAMC20G) || (SAMC21G)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA12C_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA13C_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3
+
+ #ifdef ID_SERCOM4
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PB08D_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PB09D_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PB10D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PB11D_SERCOM4_PAD3
+ #endif
+
+ #ifdef ID_SERCOM5
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PB02D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PB03D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PB22D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PB23D_SERCOM5_PAD3
+ #endif
+
+#elif (SAMC20J) || (SAMC21J)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA12C_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA13C_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA14C_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA15C_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA22C_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA23C_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA24C_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA25C_SERCOM3_PAD3
+
+ #ifdef ID_SERCOM4
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PB08D_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PB09D_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PB10D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PB11D_SERCOM4_PAD3
+ #endif
+
+ #ifdef ID_SERCOM5
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PB02D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PB03D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PB00D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PB01D_SERCOM5_PAD3
+ #endif
+
+#elif (SAMDA1)
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3
+
+ #if (SAMDA1E)
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */
+ #define SERCOM4_PAD1_DEFAULT 0 /* No available pin */
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3
+ #else
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PA12D_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PA13D_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3
+ #endif
+
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3
+
+#elif (SAML21E) || (SAMR30E)
+
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3
+
+ #if !SAM_PART_IS_DEFINED(SAML21E18A) && !SAM_PART_IS_DEFINED(SAMR30E18A)
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT 0 /* No available pin */
+ #define SERCOM4_PAD1_DEFAULT 0 /* No available pin */
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3
+
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3
+ #endif
+
+#else
+ /* SERCOM0 */
+ #define SERCOM0_PAD0_DEFAULT PINMUX_PA04D_SERCOM0_PAD0
+ #define SERCOM0_PAD1_DEFAULT PINMUX_PA05D_SERCOM0_PAD1
+ #define SERCOM0_PAD2_DEFAULT PINMUX_PA06D_SERCOM0_PAD2
+ #define SERCOM0_PAD3_DEFAULT PINMUX_PA07D_SERCOM0_PAD3
+
+ /* SERCOM1 */
+#if SAM_PART_IS_DEFINED(SAMD21G15L) || SAM_PART_IS_DEFINED(SAMD21G16L)
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA16C_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA17C_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA18C_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA19C_SERCOM1_PAD3
+#else
+ #define SERCOM1_PAD0_DEFAULT PINMUX_PA00D_SERCOM1_PAD0
+ #define SERCOM1_PAD1_DEFAULT PINMUX_PA01D_SERCOM1_PAD1
+ #define SERCOM1_PAD2_DEFAULT PINMUX_PA30D_SERCOM1_PAD2
+ #define SERCOM1_PAD3_DEFAULT PINMUX_PA31D_SERCOM1_PAD3
+#endif
+
+ /* SERCOM2 */
+ #define SERCOM2_PAD0_DEFAULT PINMUX_PA08D_SERCOM2_PAD0
+ #define SERCOM2_PAD1_DEFAULT PINMUX_PA09D_SERCOM2_PAD1
+ #define SERCOM2_PAD2_DEFAULT PINMUX_PA10D_SERCOM2_PAD2
+ #define SERCOM2_PAD3_DEFAULT PINMUX_PA11D_SERCOM2_PAD3
+
+ /* SERCOM3 */
+ #define SERCOM3_PAD0_DEFAULT PINMUX_PA16D_SERCOM3_PAD0
+ #define SERCOM3_PAD1_DEFAULT PINMUX_PA17D_SERCOM3_PAD1
+ #define SERCOM3_PAD2_DEFAULT PINMUX_PA18D_SERCOM3_PAD2
+ #define SERCOM3_PAD3_DEFAULT PINMUX_PA19D_SERCOM3_PAD3
+
+ #if !(SAMD20E || SAMD21E)
+ /* SERCOM4 */
+ #define SERCOM4_PAD0_DEFAULT PINMUX_PA12D_SERCOM4_PAD0
+ #define SERCOM4_PAD1_DEFAULT PINMUX_PA13D_SERCOM4_PAD1
+ #define SERCOM4_PAD2_DEFAULT PINMUX_PA14D_SERCOM4_PAD2
+ #define SERCOM4_PAD3_DEFAULT PINMUX_PA15D_SERCOM4_PAD3
+
+ /* SERCOM5 */
+ #define SERCOM5_PAD0_DEFAULT PINMUX_PA22D_SERCOM5_PAD0
+ #define SERCOM5_PAD1_DEFAULT PINMUX_PA23D_SERCOM5_PAD1
+ #define SERCOM5_PAD2_DEFAULT PINMUX_PA24D_SERCOM5_PAD2
+ #define SERCOM5_PAD3_DEFAULT PINMUX_PA25D_SERCOM5_PAD3
+ #endif
+
+#endif
+
+#endif /* SERCOM_PINOUT_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi/module_config/conf_spi.h b/atmel-samd/asf/sam0/drivers/sercom/spi/module_config/conf_spi.h
new file mode 100644
index 000000000..18b4f76ef
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi/module_config/conf_spi.h
@@ -0,0 +1,55 @@
+/**
+ * \file
+ *
+ * \brief SAM SPI configuration
+ *
+ * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+
+#ifndef CONF_SPI_H_INCLUDED
+# define CONF_SPI_H_INCLUDED
+
+# define CONF_SPI_MASTER_ENABLE true
+# define CONF_SPI_SLAVE_ENABLE true
+
+#endif /* CONF_SPI_H_INCLUDED */
+
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi/spi.c b/atmel-samd/asf/sam0/drivers/sercom/spi/spi.c
new file mode 100644
index 000000000..c0b4acb4a
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi/spi.c
@@ -0,0 +1,1265 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include "spi.h"
+
+/**
+ * \brief Resets the SPI module
+ *
+ * This function will reset the SPI module to its power on default values and
+ * disable it.
+ *
+ * \param[in,out] module Pointer to the software instance struct
+ */
+void spi_reset(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Disable the module */
+ spi_disable(module);
+
+ while (spi_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+
+ /* Software reset the module */
+ spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST;
+}
+
+/**
+ * \brief Set the baudrate of the SPI module
+ *
+ * This function will set the baudrate of the SPI module.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] baudrate The baudrate wanted
+ *
+ * \return The status of the configuration.
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ * \retval STATUS_OK If the configuration was written
+ */
+enum status_code spi_set_baudrate(
+ struct spi_module *const module,
+ uint32_t baudrate)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(baudrate);
+ Assert(module->hw);
+
+ /* Value to write to BAUD register */
+ uint16_t baud = 0;
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Disable the module */
+ spi_disable(module);
+
+ while (spi_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+
+ /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index);
+
+ /* Get baud value, based on baudrate and the internal clock frequency */
+ enum status_code error_code = _sercom_get_sync_baud_val(
+ baudrate, internal_clock, &baud);
+
+ if (error_code != STATUS_OK) {
+ /* Baud rate calculation error, return status code */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ spi_module->BAUD.reg = (uint8_t)baud;
+
+ while (spi_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+
+ /* Enable the module */
+ spi_enable(module);
+
+ while (spi_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+
+ return STATUS_OK;
+}
+
+# if CONF_SPI_SLAVE_ENABLE == true
+/**
+ * \internal Clears the Transmit Complete interrupt flag.
+ *
+ * \param[in] module Pointer to the software instance struct
+ */
+static void _spi_clear_tx_complete_flag(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Clear interrupt flag */
+ spi_module->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+}
+# endif
+
+/**
+ * \internal Writes an SPI SERCOM configuration to the hardware module.
+ *
+ * This function will write out a given configuration to the hardware module.
+ * Can only be done when the module is disabled.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return The status of the configuration.
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ * \retval STATUS_OK If the configuration was written
+ */
+static enum status_code _spi_set_config(
+ struct spi_module *const module,
+ const struct spi_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(config);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+ Sercom *const hw = module->hw;
+
+ struct system_pinmux_config pin_conf;
+ system_pinmux_get_config_defaults(&pin_conf);
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
+ if(config->mode == SPI_MODE_SLAVE) {
+ pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
+ }
+
+ uint32_t pad_pinmuxes[] = {
+ config->pinmux_pad0, config->pinmux_pad1,
+ config->pinmux_pad2, config->pinmux_pad3
+ };
+
+ /* Configure the SERCOM pins according to the user configuration */
+ for (uint8_t pad = 0; pad < 4; pad++) {
+ uint32_t current_pinmux = pad_pinmuxes[pad];
+
+ if (current_pinmux == PINMUX_DEFAULT) {
+ current_pinmux = _sercom_get_default_pad(hw, pad);
+ }
+
+ if (current_pinmux != PINMUX_UNUSED) {
+ pin_conf.mux_position = current_pinmux & 0xFFFF;
+ system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
+ }
+ }
+
+ module->mode = config->mode;
+ module->character_size = config->character_size;
+ module->receiver_enabled = config->receiver_enable;
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ module->master_slave_select_enable = config->master_slave_select_enable;
+# endif
+
+# if CONF_SPI_MASTER_ENABLE == true
+ /* Value to write to BAUD register */
+ uint16_t baud = 0;
+# endif
+ /* Value to write to CTRLA register */
+ uint32_t ctrla = 0;
+ /* Value to write to CTRLB register */
+ uint32_t ctrlb = 0;
+
+# if CONF_SPI_MASTER_ENABLE == true
+ /* Find baud value and write it */
+ if (config->mode == SPI_MODE_MASTER) {
+ /* Find frequency of the internal SERCOMi_GCLK_ID_CORE */
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ uint32_t internal_clock = system_gclk_chan_get_hz(gclk_index);
+
+ /* Get baud value, based on baudrate and the internal clock frequency */
+ enum status_code error_code = _sercom_get_sync_baud_val(
+ config->mode_specific.master.baudrate,
+ internal_clock, &baud);
+
+ if (error_code != STATUS_OK) {
+ /* Baud rate calculation error, return status code */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ spi_module->BAUD.reg = (uint8_t)baud;
+ }
+# endif
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (config->mode == SPI_MODE_SLAVE) {
+ /* Set frame format */
+ ctrla = config->mode_specific.slave.frame_format;
+
+ /* Set address mode */
+ ctrlb = config->mode_specific.slave.address_mode;
+
+ /* Set address and address mask*/
+ spi_module->ADDR.reg |=
+ (config->mode_specific.slave.address << SERCOM_SPI_ADDR_ADDR_Pos) |
+ (config->mode_specific.slave.address_mask << SERCOM_SPI_ADDR_ADDRMASK_Pos);
+
+ if (config->mode_specific.slave.preload_enable) {
+ /* Enable pre-loading of shift register */
+ ctrlb |= SERCOM_SPI_CTRLB_PLOADEN;
+ }
+ }
+# endif
+ /* Set data order */
+ ctrla |= config->data_order;
+
+ /* Set clock polarity and clock phase */
+ ctrla |= config->transfer_mode;
+
+ /* Set MUX setting */
+ ctrla |= config->mux_setting;
+
+ /* Set SPI character size */
+ ctrlb |= config->character_size;
+
+ /* Set whether module should run in standby. */
+ if (config->run_in_standby || system_is_debugger_present()) {
+ ctrla |= SERCOM_SPI_CTRLA_RUNSTDBY;
+ }
+
+ if (config->receiver_enable) {
+ /* Enable receiver */
+ ctrlb |= SERCOM_SPI_CTRLB_RXEN;
+ }
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ if (config->select_slave_low_detect_enable) {
+ /* Enable Slave Select Low Detect */
+ ctrlb |= SERCOM_SPI_CTRLB_SSDE;
+ }
+# endif
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ if (config->master_slave_select_enable) {
+ /* Enable Master Slave Select */
+ ctrlb |= SERCOM_SPI_CTRLB_MSSEN;
+ }
+# endif
+ /* Write CTRLA register */
+ spi_module->CTRLA.reg |= ctrla;
+
+ /* Write CTRLB register */
+ spi_module->CTRLB.reg |= ctrlb;
+
+ return STATUS_OK;
+}
+
+#if SPI_CALLBACK_MODE == false
+/**
+ * \internal Checks an SPI config against current set config
+ *
+ * This function will check that the config does not alter the
+ * configuration of the module. If the new config changes any
+ * setting, the initialization will be discarded.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] config Pointer to the configuration struct
+ *
+ * \return The status of the configuration.
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ * \retval STATUS_ERR_DENIED If configuration was different from previous
+ * \retval STATUS_OK If the configuration was written
+ */
+static enum status_code _spi_check_config(
+ struct spi_module *const module,
+ const struct spi_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(config);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+ Sercom *const hw = module->hw;
+
+ uint32_t pad_pinmuxes[] = {
+ config->pinmux_pad0, config->pinmux_pad1,
+ config->pinmux_pad2, config->pinmux_pad3
+ };
+
+ /* Compare the current SERCOM pins against the user configuration */
+ for (uint8_t pad = 0; pad < 4; pad++) {
+ uint32_t current_pinmux = pad_pinmuxes[pad];
+
+ if (current_pinmux == PINMUX_DEFAULT) {
+ current_pinmux = _sercom_get_default_pad(hw, pad);
+ }
+
+ if (current_pinmux == PINMUX_UNUSED) {
+ continue;
+ }
+
+ if ((current_pinmux & 0xFFFF) !=
+ system_pinmux_pin_get_mux_position(current_pinmux >> 16)) {
+ module->hw = NULL;
+ return STATUS_ERR_DENIED;
+ }
+ }
+
+# if CONF_SPI_MASTER_ENABLE == true
+ /* Value to read BAUD register */
+ uint16_t baud;
+ uint32_t external_clock = system_gclk_chan_get_hz(SERCOM_GCLK_ID);
+# endif
+ /* Value to read CTRLA, CTRLB and ADDR register */
+ uint32_t ctrla = 0;
+ uint32_t ctrlb = 0;
+# if CONF_SPI_SLAVE_ENABLE == true
+ uint32_t addr = 0;
+# endif
+
+# if CONF_SPI_MASTER_ENABLE == true
+ /* Find baud value and compare it */
+ if (config->mode == SPI_MODE_MASTER) {
+ enum status_code error_code = _sercom_get_sync_baud_val(
+ config->mode_specific.master.baudrate,
+ external_clock, &baud);
+
+ if (error_code != STATUS_OK) {
+ /* Baud rate calculation error, return status code */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ if (spi_module->BAUD.reg != (uint8_t)baud) {
+ return STATUS_ERR_DENIED;
+ }
+
+ ctrla |= SERCOM_SPI_CTRLA_MODE(0x3);
+ }
+# endif
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (config->mode == SPI_MODE_SLAVE) {
+
+ /* Set frame format */
+ ctrla |= config->mode_specific.slave.frame_format;
+
+ /* Set address mode */
+ ctrlb |= config->mode_specific.slave.address_mode;
+
+ /* Set address and address mask*/
+ addr |= (config->mode_specific.slave.address << SERCOM_SPI_ADDR_ADDR_Pos) |
+ (config->mode_specific.slave.address_mask << SERCOM_SPI_ADDR_ADDRMASK_Pos);
+ if (spi_module->CTRLA.reg != addr) {
+ return STATUS_ERR_DENIED;
+ }
+
+ if (config->mode_specific.slave.preload_enable) {
+ /* Enable pre-loading of shift register */
+ ctrlb |= SERCOM_SPI_CTRLB_PLOADEN;
+ }
+ ctrla |= SERCOM_SPI_CTRLA_MODE(0x2);
+ }
+# endif
+ /* Set data order */
+ ctrla |= config->data_order;
+
+ /* Set clock polarity and clock phase */
+ ctrla |= config->transfer_mode;
+
+ /* Set MUX setting */
+ ctrla |= config->mux_setting;
+
+ /* Set SPI character size */
+ ctrlb |= config->character_size;
+
+ if (config->run_in_standby) {
+ /* Enable in sleep mode */
+ ctrla |= SERCOM_SPI_CTRLA_RUNSTDBY;
+ }
+
+ if (config->receiver_enable) {
+ /* Enable receiver */
+ ctrlb |= SERCOM_SPI_CTRLB_RXEN;
+ }
+
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ if (config->select_slave_low_detect_enable) {
+ /* Enable Slave Select Low Detect */
+ ctrlb |= SERCOM_SPI_CTRLB_SSDE;
+ }
+# endif
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ if (config->master_slave_select_enable) {
+ /* Enable Master Slave Select */
+ ctrlb |= SERCOM_SPI_CTRLB_MSSEN;
+ }
+# endif
+
+ ctrla |= SERCOM_SPI_CTRLA_ENABLE;
+
+ /* Check that same config is set */
+ if (spi_module->CTRLA.reg == ctrla &&
+ spi_module->CTRLB.reg == ctrlb) {
+ module->mode = config->mode;
+ module->character_size = config->character_size;
+ return STATUS_OK;
+ }
+
+ /* Not same config, wipe module pointer and return */
+ module->hw = NULL;
+
+ return STATUS_ERR_DENIED;
+}
+#endif
+
+/**
+ * \brief Initializes the SERCOM SPI module
+ *
+ * This function will initialize the SERCOM SPI module, based on the values
+ * of the config struct.
+ *
+ * \param[out] module Pointer to the software instance struct
+ * \param[in] hw Pointer to hardware instance
+ * \param[in] config Pointer to the config struct
+ *
+ * \return Status of the initialization.
+ * \retval STATUS_OK Module initiated correctly
+ * \retval STATUS_ERR_DENIED If module is enabled
+ * \retval STATUS_BUSY If module is busy resetting
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ */
+enum status_code spi_init(
+ struct spi_module *const module,
+ Sercom *const hw,
+ const struct spi_config *const config)
+{
+
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(hw);
+ Assert(config);
+
+ /* Initialize device instance */
+ module->hw = hw;
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Check if module is enabled. */
+ if (spi_module->CTRLA.reg & SERCOM_SPI_CTRLA_ENABLE) {
+# if SPI_CALLBACK_MODE == false
+ /* Check if config is valid */
+ return _spi_check_config(module, config);
+# else
+ return STATUS_ERR_DENIED;
+# endif
+ }
+
+ /* Check if reset is in progress. */
+ if (spi_module->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST){
+ return STATUS_BUSY;
+ }
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t pm_index, gclk_index;
+#if (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+# ifdef ID_SERCOM5
+ pm_index = MCLK_APBDMASK_SERCOM5_Pos;
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+# else
+ return STATUS_ERR_INVALID_ARG;
+# endif
+ } else {
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#elif (SAMC21)
+ if (sercom_index == 5) {
+# ifdef ID_SERCOM5
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+# else
+ return STATUS_ERR_INVALID_ARG;
+# endif
+ } else {
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#elif (SAMC20) || (SAML22)
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#else
+ pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#endif
+
+ /* Turn on module in PM */
+#if (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+# ifdef ID_SERCOM5
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
+# else
+ return STATUS_ERR_INVALID_ARG;
+# endif
+ } else {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+ }
+#else
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+#endif
+
+ /* Set up the GCLK for the module */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->generator_source;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->generator_source, false);
+
+# if CONF_SPI_MASTER_ENABLE == true
+ if (config->mode == SPI_MODE_MASTER) {
+ /* Set the SERCOM in SPI master mode */
+ spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
+ }
+# endif
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (config->mode == SPI_MODE_SLAVE) {
+ /* Set the SERCOM in SPI slave mode */
+ spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x2);
+ }
+# endif
+
+#if SPI_CALLBACK_MODE == true
+ /* Temporary variables */
+ uint8_t i;
+ uint8_t instance_index;
+
+ /* Initialize parameters */
+ for (i = 0; i < SPI_CALLBACK_N; i++) {
+ module->callback[i] = NULL;
+ }
+ module->tx_buffer_ptr = NULL;
+ module->rx_buffer_ptr = NULL;
+ module->remaining_tx_buffer_length = 0x0000;
+ module->remaining_rx_buffer_length = 0x0000;
+ module->registered_callback = 0x00;
+ module->enabled_callback = 0x00;
+ module->status = STATUS_OK;
+ module->dir = SPI_DIRECTION_IDLE;
+ module->locked = false;
+ /*
+ * Set interrupt handler and register SPI software module struct in
+ * look-up table
+ */
+ instance_index = _sercom_get_sercom_inst_index(module->hw);
+ _sercom_set_handler(instance_index, _spi_interrupt_handler);
+ _sercom_instances[instance_index] = module;
+#endif
+
+ /* Write configuration to module and return status code */
+ return _spi_set_config(module, config);
+}
+
+/**
+ * \brief Reads buffer of \c length SPI characters
+ *
+ * This function will read a buffer of data from an SPI peripheral by sending
+ * dummy SPI character if in master mode, or by waiting for data in slave mode.
+ *
+ * \note If address matching is enabled for the slave, the first character
+ * received and placed in the buffer will be the address.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[out] rx_data Data buffer for received data
+ * \param[in] length Length of data to receive
+ * \param[in] dummy 8- or 9-bit dummy byte to shift out in master mode
+ *
+ * \return Status of the read operation.
+ * \retval STATUS_OK If the read was completed
+ * \retval STATUS_ABORTED If transaction was ended by master before
+ * the entire buffer was transferred
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the
+ * timeout in slave mode
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ * \retval STATUS_ERR_OVERFLOW If the data is overflown
+ */
+enum status_code spi_read_buffer_wait(
+ struct spi_module *const module,
+ uint8_t *rx_data,
+ uint16_t length,
+ uint16_t dummy)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+# if SPI_CALLBACK_MODE == true
+ if (module->status == STATUS_BUSY) {
+ /* Check if the SPI module is busy with a job */
+ return STATUS_BUSY;
+ }
+# endif
+
+ /* Sanity check arguments */
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+# if CONF_SPI_SLAVE_ENABLE == true
+ if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) {
+ /* Clear TX complete flag */
+ _spi_clear_tx_complete_flag(module);
+ }
+# endif
+ uint16_t rx_pos = 0;
+
+ while (length--) {
+# if CONF_SPI_MASTER_ENABLE == true
+ if (module->mode == SPI_MODE_MASTER) {
+ /* Wait until the module is ready to write a character */
+ while (!spi_is_ready_to_write(module)) {
+ }
+
+ /* Send dummy SPI character to read in master mode */
+ spi_write(module, dummy);
+ }
+# endif
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (spi_is_ready_to_read(module)) {
+ break;
+ }
+ }
+ /* Check if master has ended the transaction */
+ if (spi_is_write_complete(module)) {
+ _spi_clear_tx_complete_flag(module);
+ return STATUS_ABORTED;
+ }
+
+ if (!spi_is_ready_to_read(module)) {
+ /* Not ready to read data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+# endif
+
+ /* Wait until the module is ready to read a character */
+ while (!spi_is_ready_to_read(module)) {
+ }
+
+ uint16_t received_data = 0;
+ enum status_code retval = spi_read(module, &received_data);
+
+ if (retval != STATUS_OK) {
+ /* Overflow, abort */
+ return retval;
+ }
+
+ /* Read value will be at least 8-bits long */
+ rx_data[rx_pos++] = received_data;
+
+ /* If 9-bit data, write next received byte to the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ rx_data[rx_pos++] = (received_data >> 8);
+ }
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Sends and reads a single SPI character
+ *
+ * This function will transfer a single SPI character via SPI and return the
+ * SPI character that is shifted into the shift register.
+ *
+ * In master mode the SPI character will be sent immediately and the received
+ * SPI character will be read as soon as the shifting of the data is
+ * complete.
+ *
+ * In slave mode this function will place the data to be sent into the transmit
+ * buffer. It will then block until an SPI master has shifted a complete
+ * SPI character, and the received data is available.
+ *
+ * \note The data to be sent might not be sent before the next transfer, as
+ * loading of the shift register is dependent on SCK.
+ * \note If address matching is enabled for the slave, the first character
+ * received and placed in the buffer will be the address.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] tx_data SPI character to transmit
+ * \param[out] rx_data Pointer to store the received SPI character
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If the operation was completed
+ * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the
+ * timeout in slave mode
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ * \retval STATUS_ERR_OVERFLOW If the incoming data is overflown
+ */
+enum status_code spi_transceive_wait(
+ struct spi_module *const module,
+ uint16_t tx_data,
+ uint16_t *rx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+# if SPI_CALLBACK_MODE == true
+ if (module->status == STATUS_BUSY) {
+ /* Check if the SPI module is busy with a job */
+ return STATUS_BUSY;
+ }
+# endif
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ uint16_t j;
+# endif
+ enum status_code retval = STATUS_OK;
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (j = 0; j <= SPI_TIMEOUT; j++) {
+ if (spi_is_ready_to_write(module)) {
+ break;
+ } else if (j == SPI_TIMEOUT) {
+ /* Not ready to write data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ }
+# endif
+ /* Wait until the module is ready to write the character */
+ while (!spi_is_ready_to_write(module)) {
+ }
+
+ /* Write data */
+ spi_write(module, tx_data);
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (j = 0; j <= SPI_TIMEOUT; j++) {
+ if (spi_is_ready_to_read(module)) {
+ break;
+ } else if (j == SPI_TIMEOUT) {
+ /* Not ready to read data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+ }
+# endif
+
+ /* Wait until the module is ready to read the character */
+ while (!spi_is_ready_to_read(module)) {
+ }
+
+ /* Read data */
+ retval = spi_read(module, rx_data);
+
+ return retval;
+}
+
+ /**
+ * \brief Selects slave device
+ *
+ * This function will drive the slave select pin of the selected device low or
+ * high depending on the select Boolean.
+ * If slave address recognition is enabled, the address will be sent to the
+ * slave when selecting it.
+ *
+ * \param[in] module Pointer to the software module struct
+ * \param[in] slave Pointer to the attached slave
+ * \param[in] select Boolean stating if the slave should be selected or
+ * deselected
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If the slave device was selected
+ * \retval STATUS_ERR_UNSUPPORTED_DEV If the SPI module is operating in slave
+ * mode
+ * \retval STATUS_BUSY If the SPI module is not ready to write
+ * the slave address
+ */
+enum status_code spi_select_slave(
+ struct spi_module *const module,
+ struct spi_slave_inst *const slave,
+ const bool select)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(slave);
+
+ /* Check that the SPI module is operating in master mode */
+ if (module->mode != SPI_MODE_MASTER) {
+ return STATUS_ERR_UNSUPPORTED_DEV;
+ }
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ if(!(module->master_slave_select_enable))
+# endif
+ {
+ if (select) {
+ /* Check if address recognition is enabled */
+ if (slave->address_enabled) {
+ /* Check if the module is ready to write the address */
+ if (!spi_is_ready_to_write(module)) {
+ /* Not ready, do not select slave and return */
+ port_pin_set_output_level(slave->ss_pin, true);
+ return STATUS_BUSY;
+ }
+
+ /* Drive Slave Select low */
+ port_pin_set_output_level(slave->ss_pin, false);
+
+ /* Write address to slave */
+ spi_write(module, slave->address);
+
+ if (!(module->receiver_enabled)) {
+ /* Flush contents of shift register shifted back from slave */
+ while (!spi_is_ready_to_read(module)) {
+ }
+ uint16_t flush = 0;
+ spi_read(module, &flush);
+ }
+ } else {
+ /* Drive Slave Select low */
+ port_pin_set_output_level(slave->ss_pin, false);
+ }
+ } else {
+ /* Drive Slave Select high */
+ port_pin_set_output_level(slave->ss_pin, true);
+ }
+ }
+ return STATUS_OK;
+}
+
+/**
+ * \brief Sends a buffer of \c length SPI characters
+ *
+ * This function will send a buffer of SPI characters via the SPI
+ * and discard any data that is received. To both send and receive a buffer of
+ * data, use the \ref spi_transceive_buffer_wait function.
+ *
+ * Note that this function does not handle the _SS (slave select) pin(s) in
+ * master mode; this must be handled by the user application.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] tx_data Pointer to the buffer to transmit
+ * \param[in] length Number of SPI characters to transfer
+ *
+ * \return Status of the write operation.
+ * \retval STATUS_OK If the write was completed
+ * \retval STATUS_ABORTED If transaction was ended by master before
+ * entire buffer was transferred
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the
+ * timeout in slave mode
+ */
+enum status_code spi_write_buffer_wait(
+ struct spi_module *const module,
+ const uint8_t *tx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+# if SPI_CALLBACK_MODE == true
+ if (module->status == STATUS_BUSY) {
+ /* Check if the SPI module is busy with a job */
+ return STATUS_BUSY;
+ }
+# endif
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) {
+ /* Clear TX complete flag */
+ _spi_clear_tx_complete_flag(module);
+ }
+# endif
+
+ uint16_t tx_pos = 0;
+ uint16_t flush_length = length;
+
+ /* Write block */
+ while (length--) {
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (spi_is_ready_to_write(module)) {
+ break;
+ }
+ }
+ /* Check if master has ended the transaction */
+ if (spi_is_write_complete(module)) {
+ _spi_clear_tx_complete_flag(module);
+ return STATUS_ABORTED;
+ }
+
+ if (!spi_is_ready_to_write(module)) {
+ /* Not ready to write data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+# endif
+
+ /* Wait until the module is ready to write a character */
+ while (!spi_is_ready_to_write(module)) {
+ }
+
+ /* Write value will be at least 8-bits long */
+ uint16_t data_to_send = tx_data[tx_pos++];
+
+ /* If 9-bit data, get next byte to send from the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ data_to_send |= (tx_data[tx_pos++] << 8);
+ }
+
+ /* Write the data to send */
+ spi_write(module, data_to_send);
+
+ if (module->receiver_enabled) {
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (length && spi_is_ready_to_write(module)) {
+ data_to_send = tx_data[tx_pos++];
+ /* If 9-bit data, get next byte to send from the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ data_to_send |= (tx_data[tx_pos++] << 8);
+ }
+
+ /* Write the data to send */
+ spi_write(module, data_to_send);
+ length--;
+ }
+ if (spi_is_ready_to_read(module)) {
+ break;
+ }
+ }
+
+ /* Check if master has ended the transaction */
+ if (spi_is_write_complete(module)) {
+ _spi_clear_tx_complete_flag(module);
+ return STATUS_ABORTED;
+ }
+
+ if (!spi_is_ready_to_read(module)) {
+ /* Not ready to read data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+# endif
+
+ while (!spi_is_ready_to_read(module)) {
+ }
+
+ /* Flush read buffer */
+ uint16_t flush;
+ spi_read(module, &flush);
+ flush_length--;
+ }
+ }
+
+# if CONF_SPI_MASTER_ENABLE == true
+ if (module->mode == SPI_MODE_MASTER) {
+ /* Wait for last byte to be transferred */
+ while (!spi_is_write_complete(module)) {
+ }
+ }
+# endif
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (module->mode == SPI_MODE_SLAVE) {
+ if (module->receiver_enabled) {
+ while (flush_length) {
+ /* Start timeout period for slave */
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (spi_is_ready_to_read(module)) {
+ break;
+ }
+ }
+ if (!spi_is_ready_to_read(module)) {
+ /* Not ready to read data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ /* Flush read buffer */
+ uint16_t flush;
+ spi_read(module, &flush);
+ flush_length--;
+ }
+ }
+ }
+# endif
+ return STATUS_OK;
+}
+
+/**
+ * \brief Sends and receives a buffer of \c length SPI characters
+ *
+ * This function will send and receive a buffer of data via the SPI.
+ *
+ * In master mode the SPI characters will be sent immediately and the
+ * received SPI character will be read as soon as the shifting of the SPI
+ * character is complete.
+ *
+ * In slave mode this function will place the data to be sent into the transmit
+ * buffer. It will then block until an SPI master has shifted the complete
+ * buffer and the received data is available.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] tx_data Pointer to the buffer to transmit
+ * \param[out] rx_data Pointer to the buffer where received data will be stored
+ * \param[in] length Number of SPI characters to transfer
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If the operation was completed
+ * \retval STATUS_ERR_INVALID_ARG If invalid argument(s) were provided
+ * \retval STATUS_ERR_TIMEOUT If the operation was not completed within the
+ * timeout in slave mode
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ * \retval STATUS_ERR_OVERFLOW If the data is overflown
+ */
+enum status_code spi_transceive_buffer_wait(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+# if SPI_CALLBACK_MODE == true
+ if (module->status == STATUS_BUSY) {
+ /* Check if the SPI module is busy with a job */
+ return STATUS_BUSY;
+ }
+# endif
+
+ /* Sanity check arguments */
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if ((module->mode == SPI_MODE_SLAVE) && (spi_is_write_complete(module))) {
+ /* Clear TX complete flag */
+ _spi_clear_tx_complete_flag(module);
+ }
+# endif
+
+ uint16_t tx_pos = 0;
+ uint16_t rx_pos = 0;
+ uint16_t rx_length = length;
+
+ /* Send and receive buffer */
+ while (length--) {
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (spi_is_ready_to_write(module)) {
+ break;
+ }
+ }
+ /* Check if master has ended the transaction */
+ if (spi_is_write_complete(module)) {
+ _spi_clear_tx_complete_flag(module);
+ return STATUS_ABORTED;
+ }
+
+ if (!spi_is_ready_to_write(module)) {
+ /* Not ready to write data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+# endif
+
+ /* Wait until the module is ready to write a character */
+ while (!spi_is_ready_to_write(module)) {
+ }
+
+ /* Write value will be at least 8-bits long */
+ uint16_t data_to_send = tx_data[tx_pos++];
+
+ /* If 9-bit data, get next byte to send from the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ data_to_send |= (tx_data[tx_pos++] << 8);
+ }
+
+ /* Write the data to send */
+ spi_write(module, data_to_send);
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* Start timeout period for slave */
+ if (module->mode == SPI_MODE_SLAVE) {
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (spi_is_ready_to_write(module)) {
+ data_to_send = tx_data[tx_pos++];
+ /* If 9-bit data, get next byte to send from the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ data_to_send |= (tx_data[tx_pos++] << 8);
+ }
+
+ /* Write the data to send */
+ spi_write(module, data_to_send);
+ length--;
+ }
+ if (spi_is_ready_to_read(module)) {
+ break;
+ }
+ }
+ /* Check if master has ended the transaction */
+ if (spi_is_write_complete(module)) {
+ _spi_clear_tx_complete_flag(module);
+ return STATUS_ABORTED;
+ }
+
+ if (!spi_is_ready_to_read(module)) {
+ /* Not ready to read data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+# endif
+
+ /* Wait until the module is ready to read a character */
+ while (!spi_is_ready_to_read(module)) {
+ }
+
+ enum status_code retval;
+ uint16_t received_data = 0;
+ rx_length--;
+
+ retval = spi_read(module, &received_data);
+
+ if (retval != STATUS_OK) {
+ /* Overflow, abort */
+ return retval;
+ }
+
+ /* Read value will be at least 8-bits long */
+ rx_data[rx_pos++] = received_data;
+
+ /* If 9-bit data, write next received byte to the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ rx_data[rx_pos++] = (received_data >> 8);
+ }
+ }
+
+# if CONF_SPI_MASTER_ENABLE == true
+ if (module->mode == SPI_MODE_MASTER) {
+ /* Wait for last byte to be transferred */
+ while (!spi_is_write_complete(module)) {
+ }
+ }
+# endif
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (module->mode == SPI_MODE_SLAVE) {
+ while (rx_length) {
+ /* Start timeout period for slave */
+ for (uint32_t i = 0; i <= SPI_TIMEOUT; i++) {
+ if (spi_is_ready_to_read(module)) {
+ break;
+ }
+ }
+ if (!spi_is_ready_to_read(module)) {
+ /* Not ready to read data within timeout period */
+ return STATUS_ERR_TIMEOUT;
+ }
+ enum status_code retval;
+ uint16_t received_data = 0;
+ rx_length--;
+
+ retval = spi_read(module, &received_data);
+
+ if (retval != STATUS_OK) {
+ /* Overflow, abort */
+ return retval;
+ }
+ /* Read value will be at least 8-bits long */
+ rx_data[rx_pos++] = received_data;
+
+ /* If 9-bit data, write next received byte to the buffer */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ rx_data[rx_pos++] = (received_data >> 8);
+ }
+ }
+ }
+# endif
+ return STATUS_OK;
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi/spi.h b/atmel-samd/asf/sam0/drivers/sercom/spi/spi.h
new file mode 100644
index 000000000..01d21a21e
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi/spi.h
@@ -0,0 +1,1807 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SPI_H_INCLUDED
+#define SPI_H_INCLUDED
+
+/**
+ * \defgroup asfdoc_sam0_sercom_spi_group SAM Serial Peripheral Interface (SERCOM SPI) Driver
+ *
+ * This driver for Atmel&reg; | SMART ARM&reg;-based microcontrollers provides
+ * an interface for the configuration and management of the SERCOM module in
+ * its SPI mode to transfer SPI data frames. The following driver API modes
+ * are covered by this manual:
+ *
+ * - Polled APIs
+ * \if SPI_CALLBACK_MODE
+ * - Callback APIs
+ * \endif
+ *
+ * The following peripheral is used by this module:
+ * - SERCOM (Serial Communication Interface)
+ *
+ * The following devices can use this module:
+ * - Atmel | SMART SAM D20/D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D09/D10/D11
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM DA1
+ * - Atmel | SMART SAM C20/C21
+ * - Atmel | SMART SAM R30
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_sercom_spi_prerequisites
+ * - \ref asfdoc_sam0_sercom_spi_module_overview
+ * - \ref asfdoc_sam0_sercom_spi_special_considerations
+ * - \ref asfdoc_sam0_sercom_spi_extra_info
+ * - \ref asfdoc_sam0_sercom_spi_examples
+ * - \ref asfdoc_sam0_sercom_spi_api_overview
+ *
+ * \section asfdoc_sam0_sercom_spi_prerequisites Prerequisites
+ * There are no prerequisites.
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_module_overview Module Overview
+ * The Serial Peripheral Interface (SPI) is a high-speed synchronous data
+ * transfer interface using three or four pins. It allows fast communication
+ * between a master device and one or more peripheral devices.
+ *
+ * A device connected to the bus must act as a master or a slave. The master
+ * initiates and controls all data transactions.
+ * The SPI master initiates a communication cycle by pulling low the Slave
+ * Select (SS) pin of the desired slave. The Slave Select pin is active low.
+ * Master and slave prepare data to be sent in their respective shift
+ * registers, and the master generates the required clock pulses on the SCK
+ * line to interchange data. Data is always shifted from master to slave on
+ * the Master Out - Slave In (MOSI) line, and from slave to master on the
+ * Master In - Slave Out (MISO) line. After each data transfer, the master can
+ * synchronize to the slave by pulling the SS line high.
+ *
+ * \subsection asfdoc_sam0_sercom_spi_module_features Driver Feature Macro Definition
+ * <table>
+ * <tr>
+ * <th>Driver feature macro</th>
+ * <th>Supported devices</th>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_SPI_SLAVE_SELECT_LOW_DETECT</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_SPI_HARDWARE_SLAVE_SELECT</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_SPI_ERROR_INTERRUPT</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_SPI_SYNC_SCHEME_VERSION_2</td>
+ * <td>SAM D21/R21/D10/D11/L21/L22/DA1/C20/C21/R30</td>
+ * </tr>
+ * </table>
+ * \note The specific features are only available in the driver when the
+ * selected device supports those features.
+ *
+ * \subsection asfdoc_sam0_sercom_spi_bus SPI Bus Connection
+ * In \ref asfdoc_sam0_spi_connection_example "the figure below", the
+ * connection between one master and one slave is shown.
+ *
+ * \anchor asfdoc_sam0_spi_connection_example
+ * \dot
+ * digraph spi_slaves_par {
+ * subgraph cluster_spi_master {
+ * shift_reg [label="Shift register", shape=box];
+ * mosi_m [label="MOSI", shape=none];
+ * miso_m [label="MISO", shape=none];
+ * sck_m [label="SCK", shape=none];
+ * ss_m [label="GPIO pin", shape=none];
+ * {rank=same; mosi_m miso_m sck_m ss_m}
+ * label="SPI Master";
+ * }
+ * subgraph cluster_spi_slave {
+ * mosi_s [label="MOSI", shape=none];
+ * miso_s [label="MISO", shape=none];
+ * sck_s [label="SCK", shape=none];
+ * ss_s [label="SS", shape=none];
+ * shift_reg_s [label="Shift register", shape=box];
+ * {rank=same; mosi_s miso_s sck_s ss_s}
+ * label="SPI Slave";
+ * rankdir=LR;
+ * }
+ * shift_reg:e -> mosi_m:w [label=""];
+ * mosi_m:e -> mosi_s:w [label=""];
+ * mosi_s:e -> shift_reg_s:w [label=""];
+ * miso_s:w -> miso_m:e [label=""];
+ * sck_m -> sck_s;
+ * ss_m -> ss_s;
+ * shift_reg_s:se -> miso_s:e [label=""];
+ * miso_m:w -> shift_reg:sw [label=""];
+ * rankdir=LR;
+ * }
+ * \enddot
+ *
+ * The different lines are as follows:
+ * - \b MISO Master Input Slave Output. The line where the data is shifted
+ * out from the slave and into the master.
+ * - \b MOSI Master Output Slave Input. The line where the data is shifted
+ * out from the master and into the slave.
+ * - \b SCK Serial Clock. Generated by the master device.
+ * - \b SS Slave Select. To initiate a transaction, the master must pull this
+ * line low.
+ *
+ * If the bus consists of several SPI slaves, they can be connected in parallel
+ * and the SPI master can use general I/O pins to control separate SS lines to
+ * each slave on the bus.
+ *
+ * It is also possible to connect all slaves in series. In this configuration,
+ * a common SS is provided to \c N slaves, enabling them simultaneously. The
+ * MISO from the \c N-1 slaves is connected to the MOSI on the next slave. The
+ * \c N<SUP>th</SUP> slave connects its MISO back to the master. For a
+ * complete transaction, the master must shift \c N+1 characters.
+ *
+ * \subsection asfdoc_sam0_sercom_spi_chsize SPI Character Size
+ * The SPI character size is configurable to eight or nine bits.
+ *
+ * \subsection asfdoc_sam0_sercom_spi_master_mode Master Mode
+ * When configured as a master, the SS pin will be configured as an output.
+ *
+ * \subsubsection asfdoc_sam0_sercom_spi_master_mode_data_transfer Data Transfer
+ * Writing a character will start the SPI clock generator, and
+ * the character is transferred to the shift register when the shift
+ * register is empty.
+ * Once this is done, a new character can be written.
+ * As each character is shifted out from the master, a character is shifted in
+ * from the slave. If the receiver is enabled, the data is moved to the receive
+ * buffer at the completion of the frame and can be read.
+ *
+ * \subsection asfdoc_sam0_sercom_spi_slave_mode Slave Mode
+ * When configured as a slave, the SPI interface will remain inactive with MISO
+ * tri-stated as long as the SS pin is driven high.
+ *
+ * \subsubsection asfdoc_sam0_sercom_spi_slave_mode_data_transfer_slave Data Transfer
+ * The data register can be updated at any time.
+ * As the SPI slave shift register is clocked by SCK, a minimum of three SCK
+ * cycles are needed from the time new data is written, until the character is
+ * ready to be shifted out. If the shift register has not been loaded with
+ * data, the current contents will be transmitted.
+ *
+ * If constant transmission of data is needed in SPI slave mode, the system
+ * clock should be faster than SCK.
+ * If the receiver is enabled, the received character can be read from the
+ * receive buffer. When SS line is driven high, the slave will not receive any
+ * additional data.
+ *
+ * \subsubsection asfdoc_sam0_sercom_spi_slave_mode_addr_recognition Address Recognition
+ * When the SPI slave is configured with address recognition, the first
+ * character in a transaction is checked for an address match. If there is a
+ * match, the MISO output is enabled and the transaction is processed.
+ * If the address does not match, the complete transaction is ignored.
+ *
+ * If the device is asleep, it can be woken up by an address match in order
+ * to process the transaction.
+ *
+ * \note In master mode, an address packet is written by the
+ * \ref spi_select_slave function if the address_enabled configuration is
+ * set in the \ref spi_slave_inst_config struct.
+ *
+ * \subsection asfdoc_sam0_sercom_spi_data_modes Data Modes
+ * There are four combinations of SCK phase and polarity with respect to
+ * serial data. \ref asfdoc_sam0_spi_mode_table "The table below" shows the
+ * clock polarity (CPOL) and clock phase (CPHA) in the different modes.
+ * <i>Leading edge</i> is the first clock edge in a clock cycle and
+ * <i>trailing edge</i> is the last clock edge in a clock cycle.
+ *
+ * \anchor asfdoc_sam0_spi_mode_table
+ * <table>
+ * <caption>SPI Data Modes</caption>
+ * <tr>
+ * <th>Mode</th>
+ * <th>CPOL</th>
+ * <th>CPHA</th>
+ * <th>Leading Edge</th>
+ * <th>Trailing Edge</th>
+ * </tr>
+ * <tr>
+ * <td> 0 </td>
+ * <td> 0 </td>
+ * <td> 0 </td>
+ * <td> Rising, Sample </td>
+ * <td> Falling, Setup </td>
+ * </tr>
+ * <tr>
+ * <td> 1 </td>
+ * <td> 0 </td>
+ * <td> 1 </td>
+ * <td> Rising, Setup </td>
+ * <td> Falling, Sample </td>
+ * </tr>
+ * <tr>
+ * <td> 2 </td>
+ * <td> 1 </td>
+ * <td> 0 </td>
+ * <td> Falling, Sample </td>
+ * <td> Rising, Setup </td>
+ * </tr>
+ * <tr>
+ * <td> 3 </td>
+ * <td> 1 </td>
+ * <td> 1 </td>
+ * <td> Falling, Setup </td>
+ * <td> Rising, Sample </td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \subsection asfdoc_sam0_sercom_spi_pads SERCOM Pads
+ * The SERCOM pads are automatically configured as seen in
+ * \ref asfdoc_sam0_spi_sercom_pad_table "the table below". If the receiver
+ * is disabled, the data input (MISO for master, MOSI for slave) can be used
+ * for other purposes.
+ *
+ * In master mode, the SS pin(s) must be configured using the \ref spi_slave_inst
+ * struct.
+ *
+ * \anchor asfdoc_sam0_spi_sercom_pad_table
+ * <table>
+ * <caption>SERCOM SPI Pad Usages</caption>
+ * <tr>
+ * <th> Pin </th>
+ * <th> Master SPI </th>
+ * <th> Slave SPI </th>
+ * </tr>
+ * <tr>
+ * <td> MOSI </td>
+ * <td> Output </td>
+ * <td> Input </td>
+ * </tr>
+ * <tr>
+ * <td> MISO </td>
+ * <td> Input </td>
+ * <td> Output </td>
+ * </tr>
+ * <tr>
+ * <td> SCK </td>
+ * <td> Output </td>
+ * <td> Input </td>
+ * </tr>
+ * <tr>
+ * <td> SS </td>
+ * <td> User defined output enable </td>
+ * <td> Input </td>
+ * </tr>
+ * </table>
+ *
+ * \subsection asfdoc_sam0_sercom_spi_sleep_modes Operation in Sleep Modes
+ * The SPI module can operate in all sleep modes by setting the run_in_standby
+ * option in the \ref spi_config struct. The operation in slave and master mode
+ * is shown in the table below.
+ * <table>
+ * <tr>
+ * <th> run_in_standby </th>
+ * <th> Slave </th>
+ * <th> Master </th>
+ * </tr>
+ * <tr>
+ * <td> false </td>
+ * <td> Disabled, all reception is dropped </td>
+ * <td> GCLK is disabled when master is idle, wake on transmit complete </td>
+ * </tr>
+ * <tr>
+ * <td> true </td>
+ * <td> Wake on reception </td>
+ * <td> GCLK is enabled while in sleep modes, wake on all interrupts </td>
+ * </tr>
+ * </table>
+ *
+ * \subsection asfdoc_sam0_sercom_spi_clock_generation Clock Generation
+ * In SPI master mode, the clock (SCK) is generated internally using the
+ * SERCOM baudrate generator. In SPI slave mode, the clock is provided by
+ * an external master on the SCK pin. This clock is used to directly clock
+ * the SPI shift register.
+ *
+ * \section asfdoc_sam0_sercom_spi_special_considerations Special Considerations
+ * \subsection pin_mux pinmux Settings
+ * The pin MUX settings must be configured properly, as not all settings
+ * can be used in different modes of operation.
+ *
+ * \section asfdoc_sam0_sercom_spi_extra_info Extra Information
+ * For extra information, see \ref asfdoc_sam0_sercom_spi_extra. This includes:
+ * - \ref asfdoc_sam0_sercom_spi_extra_acronyms
+ * - \ref asfdoc_sam0_sercom_spi_extra_dependencies
+ * - \ref asfdoc_sam0_sercom_spi_extra_workarounds
+ * - \ref asfdoc_sam0_sercom_spi_extra_history
+ *
+ * \section asfdoc_sam0_sercom_spi_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_sercom_spi_exqsg.
+ *
+ * \section asfdoc_sam0_sercom_spi_api_overview API Overview
+ * @{
+ */
+
+#include <compiler.h>
+#include <port.h>
+#include <sercom.h>
+#include <pinmux.h>
+#include <string.h>
+#include <conf_spi.h>
+
+# if SPI_CALLBACK_MODE == true
+# include <sercom_interrupt.h>
+# endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (CONF_SPI_MASTER_ENABLE == false) && (CONF_SPI_SLAVE_ENABLE == false)
+#error "Not possible compile SPI driver, invalid driver configuration. Make sure that either/both CONF_SPI_MASTER_ENABLE/CONF_SPI_SLAVE_ENABLE is set to true."
+#endif
+
+/**
+ * \name Driver Feature Definition
+ * Define SERCOM SPI features set according to different device family.
+ * @{
+ */
+# if (SAMD21) || (SAMR21) || (SAMD11) || (SAMD10) || (SAML21) || (SAMDA1) || \
+ (SAML22) || (SAMC20) || (SAMC21) || (SAMD09) || (SAMR30) || defined(__DOXYGEN__)
+/** SPI slave select low detection. */
+# define FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+/** Slave select can be controlled by hardware. */
+# define FEATURE_SPI_HARDWARE_SLAVE_SELECT
+/** SPI with error detect feature. */
+# define FEATURE_SPI_ERROR_INTERRUPT
+/** SPI sync scheme version 2. */
+# define FEATURE_SPI_SYNC_SCHEME_VERSION_2
+# endif
+/*@}*/
+
+# ifndef PINMUX_DEFAULT
+/** Default pinmux. */
+# define PINMUX_DEFAULT 0
+# endif
+
+# ifndef PINMUX_UNUSED
+/** Unused pinmux. */
+# define PINMUX_UNUSED 0xFFFFFFFF
+# endif
+
+# ifndef SPI_TIMEOUT
+/** SPI timeout value. */
+# define SPI_TIMEOUT 10000
+# endif
+
+# if SPI_CALLBACK_MODE == true
+/**
+ * \brief SPI Callback enum
+ *
+ * Callbacks for SPI callback driver.
+ *
+ * \note For slave mode, these callbacks will be called when a transaction
+ * is ended by the master pulling Slave Select high.
+ *
+ */
+enum spi_callback {
+ /** Callback for buffer transmitted */
+ SPI_CALLBACK_BUFFER_TRANSMITTED,
+ /** Callback for buffer received */
+ SPI_CALLBACK_BUFFER_RECEIVED,
+ /** Callback for buffers transceived */
+ SPI_CALLBACK_BUFFER_TRANSCEIVED,
+ /** Callback for error */
+ SPI_CALLBACK_ERROR,
+ /**
+ * Callback for transmission ended by master before the entire buffer was
+ * read or written from slave
+ */
+ SPI_CALLBACK_SLAVE_TRANSMISSION_COMPLETE,
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ /** Callback for slave select low */
+ SPI_CALLBACK_SLAVE_SELECT_LOW,
+# endif
+# ifdef FEATURE_SPI_ERROR_INTERRUPT
+ /** Callback for combined error happen */
+ SPI_CALLBACK_COMBINED_ERROR,
+# endif
+# if !defined(__DOXYGEN__)
+ /** Number of available callbacks */
+ SPI_CALLBACK_N,
+# endif
+};
+# endif
+
+#if SPI_CALLBACK_MODE == true
+# if !defined(__DOXYGEN__)
+/**
+ * \internal SPI transfer directions
+ */
+enum _spi_direction {
+ /** Transfer direction is read */
+ SPI_DIRECTION_READ,
+ /** Transfer direction is write */
+ SPI_DIRECTION_WRITE,
+ /** Transfer direction is read and write */
+ SPI_DIRECTION_BOTH,
+ /** No transfer */
+ SPI_DIRECTION_IDLE,
+};
+# endif
+#endif
+
+/**
+ * \brief SPI Interrupt Flags
+ *
+ * Interrupt flags for the SPI module.
+ *
+ */
+enum spi_interrupt_flag {
+ /**
+ * This flag is set when the contents of the data register has been moved
+ * to the shift register and the data register is ready for new data
+ */
+ SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY = SERCOM_SPI_INTFLAG_DRE,
+ /**
+ * This flag is set when the contents of the shift register has been
+ * shifted out
+ */
+ SPI_INTERRUPT_FLAG_TX_COMPLETE = SERCOM_SPI_INTFLAG_TXC,
+ /** This flag is set when data has been shifted into the data register */
+ SPI_INTERRUPT_FLAG_RX_COMPLETE = SERCOM_SPI_INTFLAG_RXC,
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ /** This flag is set when slave select low */
+ SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW = SERCOM_SPI_INTFLAG_SSL,
+# endif
+# ifdef FEATURE_SPI_ERROR_INTERRUPT
+ /** This flag is set when combined error happen */
+ SPI_INTERRUPT_FLAG_COMBINED_ERROR = SERCOM_SPI_INTFLAG_ERROR,
+# endif
+};
+
+/**
+ * \brief SPI transfer modes enum
+ *
+ * SPI transfer mode.
+ */
+enum spi_transfer_mode {
+ /** Mode 0. Leading edge: rising, sample. Trailing edge: falling, setup */
+ SPI_TRANSFER_MODE_0 = 0,
+ /** Mode 1. Leading edge: rising, setup. Trailing edge: falling, sample */
+ SPI_TRANSFER_MODE_1 = SERCOM_SPI_CTRLA_CPHA,
+ /** Mode 2. Leading edge: falling, sample. Trailing edge: rising, setup */
+ SPI_TRANSFER_MODE_2 = SERCOM_SPI_CTRLA_CPOL,
+ /** Mode 3. Leading edge: falling, setup. Trailing edge: rising, sample */
+ SPI_TRANSFER_MODE_3 = SERCOM_SPI_CTRLA_CPHA | SERCOM_SPI_CTRLA_CPOL,
+};
+
+/**
+ * \brief SPI frame format enum
+ *
+ * Frame format for slave mode.
+ */
+enum spi_frame_format {
+ /** SPI frame */
+ SPI_FRAME_FORMAT_SPI_FRAME = SERCOM_SPI_CTRLA_FORM(0),
+ /** SPI frame with address */
+ SPI_FRAME_FORMAT_SPI_FRAME_ADDR = SERCOM_SPI_CTRLA_FORM(2),
+};
+
+/**
+ * \brief SPI signal MUX settings
+ *
+ * Set the functionality of the SERCOM pins. As not all combinations can be used
+ * in different modes of operation, proper combinations must be chosen according
+ * to the rest of the configuration.
+ *
+ * \note In master operation: DI is MISO, DO is MOSI.
+ * In slave operation: DI is MOSI, DO is MISO.
+ *
+ * See \ref asfdoc_sam0_sercom_spi_mux_settings for a description of the
+ * various MUX setting options.
+ */
+enum spi_signal_mux_setting {
+ /** SPI MUX combination A. DOPO: 0x0, DIPO: 0x0 */
+ SPI_SIGNAL_MUX_SETTING_A =
+ (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination B. DOPO: 0x0, DIPO: 0x1 */
+ SPI_SIGNAL_MUX_SETTING_B =
+ (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination C. DOPO: 0x0, DIPO: 0x2 */
+ SPI_SIGNAL_MUX_SETTING_C =
+ (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination D. DOPO: 0x0, DIPO: 0x3 */
+ SPI_SIGNAL_MUX_SETTING_D =
+ (0x0 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination E. DOPO: 0x1, DIPO: 0x0 */
+ SPI_SIGNAL_MUX_SETTING_E =
+ (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination F. DOPO: 0x1, DIPO: 0x1 */
+ SPI_SIGNAL_MUX_SETTING_F =
+ (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination G. DOPO: 0x1, DIPO: 0x2 */
+ SPI_SIGNAL_MUX_SETTING_G =
+ (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination H. DOPO: 0x1, DIPO: 0x3 */
+ SPI_SIGNAL_MUX_SETTING_H =
+ (0x1 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination I. DOPO: 0x2, DIPO: 0x0 */
+ SPI_SIGNAL_MUX_SETTING_I =
+ (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination J. DOPO: 0x2, DIPO: 0x1 */
+ SPI_SIGNAL_MUX_SETTING_J =
+ (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination K. DOPO: 0x2, DIPO: 0x2 */
+ SPI_SIGNAL_MUX_SETTING_K =
+ (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination L. DOPO: 0x2, DIPO: 0x3 */
+ SPI_SIGNAL_MUX_SETTING_L =
+ (0x2 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination M. DOPO: 0x3, DIPO: 0x0 */
+ SPI_SIGNAL_MUX_SETTING_M =
+ (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x0 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination N. DOPO: 0x3, DIPO: 0x1 */
+ SPI_SIGNAL_MUX_SETTING_N =
+ (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x1 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination O. DOPO: 0x3, DIPO: 0x2 */
+ SPI_SIGNAL_MUX_SETTING_O =
+ (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x2 << SERCOM_SPI_CTRLA_DIPO_Pos),
+ /** SPI MUX combination P. DOPO: 0x3, DIPO: 0x3 */
+ SPI_SIGNAL_MUX_SETTING_P =
+ (0x3 << SERCOM_SPI_CTRLA_DOPO_Pos) |
+ (0x3 << SERCOM_SPI_CTRLA_DIPO_Pos),
+};
+
+/**
+ * \brief SPI address modes enum
+ *
+ * For slave mode when using the SPI frame with address format.
+ *
+ */
+enum spi_addr_mode {
+ /**
+ * \c address_mask in the \ref spi_config struct is used as a mask to the register
+ */
+ SPI_ADDR_MODE_MASK = SERCOM_SPI_CTRLB_AMODE(0),
+ /**
+ * The slave responds to the two unique addresses in \c address and
+ * \c address_mask in the \ref spi_config struct
+ */
+ SPI_ADDR_MODE_UNIQUE = SERCOM_SPI_CTRLB_AMODE(1),
+ /**
+ * The slave responds to the range of addresses between and including \c address
+ * and \c address_mask in the \ref spi_config struct
+ */
+ SPI_ADDR_MODE_RANGE = SERCOM_SPI_CTRLB_AMODE(2),
+};
+
+/**
+ * \brief SPI modes enum
+ *
+ * SPI mode selection.
+ */
+enum spi_mode {
+ /** Master mode */
+ SPI_MODE_MASTER = 1,
+ /** Slave mode */
+ SPI_MODE_SLAVE = 0,
+};
+
+/**
+ * \brief SPI data order enum
+ *
+ * SPI data order.
+ *
+ */
+enum spi_data_order {
+ /** The LSB of the data is transmitted first */
+ SPI_DATA_ORDER_LSB = SERCOM_SPI_CTRLA_DORD,
+ /** The MSB of the data is transmitted first */
+ SPI_DATA_ORDER_MSB = 0,
+};
+
+/**
+ * \brief SPI character size enum
+ *
+ * SPI character size.
+ *
+ */
+enum spi_character_size {
+ /** 8-bit character */
+ SPI_CHARACTER_SIZE_8BIT = SERCOM_SPI_CTRLB_CHSIZE(0),
+ /** 9-bit character */
+ SPI_CHARACTER_SIZE_9BIT = SERCOM_SPI_CTRLB_CHSIZE(1),
+};
+
+# if SPI_CALLBACK_MODE == true
+/** Prototype for the device instance */
+struct spi_module;
+
+/** Type of the callback functions */
+typedef void (*spi_callback_t)(struct spi_module *const module);
+
+# if !defined(__DOXYGEN__)
+/** Prototype for the interrupt handler */
+extern void _spi_interrupt_handler(uint8_t instance);
+# endif
+# endif
+
+/**
+ * \brief SERCOM SPI driver software device instance structure.
+ *
+ * SERCOM SPI driver software instance structure, used to retain software state
+ * information of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved for module-internal use only.
+ */
+struct spi_module {
+# if !defined(__DOXYGEN__)
+ /** SERCOM hardware module */
+ Sercom *hw;
+ /** Module lock */
+ volatile bool locked;
+ /** SPI mode */
+ enum spi_mode mode;
+ /** SPI character size */
+ enum spi_character_size character_size;
+ /** Receiver enabled */
+ bool receiver_enabled;
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ /** Enable Hardware Slave Select */
+ bool master_slave_select_enable;
+# endif
+# if SPI_CALLBACK_MODE == true
+ /** Direction of transaction */
+ volatile enum _spi_direction dir;
+ /** Array to store callback function pointers in */
+ spi_callback_t callback[SPI_CALLBACK_N];
+ /** Buffer pointer to where the next received character will be put */
+ volatile uint8_t *rx_buffer_ptr;
+ /** Buffer pointer to where the next character will be transmitted from
+ **/
+ volatile uint8_t *tx_buffer_ptr;
+ /** Remaining characters to receive */
+ volatile uint16_t remaining_rx_buffer_length;
+ /** Remaining dummy characters to send when reading */
+ volatile uint16_t remaining_dummy_buffer_length;
+ /** Remaining characters to transmit */
+ volatile uint16_t remaining_tx_buffer_length;
+ /** Bit mask for callbacks registered */
+ uint8_t registered_callback;
+ /** Bit mask for callbacks enabled */
+ uint8_t enabled_callback;
+ /** Holds the status of the ongoing or last operation */
+ volatile enum status_code status;
+# endif
+# endif
+};
+
+/**
+ * \brief SPI peripheral slave instance structure
+ *
+ * SPI peripheral slave software instance structure, used to configure the
+ * correct SPI transfer mode settings for an attached slave. See
+ * \ref spi_select_slave.
+ */
+struct spi_slave_inst {
+ /** Pin to use as slave select */
+ uint8_t ss_pin;
+ /** Address recognition enabled in slave device */
+ bool address_enabled;
+ /** Address of slave device */
+ uint8_t address;
+};
+
+/**
+ * \brief SPI peripheral slave configuration structure
+ *
+ * SPI Peripheral slave configuration structure.
+ */
+struct spi_slave_inst_config {
+ /** Pin to use as slave select */
+ uint8_t ss_pin;
+ /** Enable address */
+ bool address_enabled;
+ /** Address of slave */
+ uint8_t address;
+};
+
+/**
+ * \brief SPI Master configuration structure
+ *
+ * SPI Master configuration structure.
+ */
+struct spi_master_config {
+ /** Baud rate */
+ uint32_t baudrate;
+};
+
+/**
+ * \brief SPI slave configuration structure
+ *
+ * SPI slave configuration structure.
+ */
+struct spi_slave_config {
+ /** Frame format */
+ enum spi_frame_format frame_format;
+ /** Address mode */
+ enum spi_addr_mode address_mode;
+ /** Address */
+ uint8_t address;
+ /** Address mask */
+ uint8_t address_mask;
+ /** Preload data to the shift register while SS is high */
+ bool preload_enable;
+};
+
+/**
+ * \brief SPI configuration structure
+ *
+ * Configuration structure for an SPI instance. This structure should be
+ * initialized by the \ref spi_get_config_defaults function before being
+ * modified by the user application.
+ */
+struct spi_config {
+ /** SPI mode */
+ enum spi_mode mode;
+ /** Data order */
+ enum spi_data_order data_order;
+ /** Transfer mode */
+ enum spi_transfer_mode transfer_mode;
+ /** MUX setting */
+ enum spi_signal_mux_setting mux_setting;
+ /** SPI character size */
+ enum spi_character_size character_size;
+ /** Enabled in sleep modes */
+ bool run_in_standby;
+ /** Enable receiver */
+ bool receiver_enable;
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ /** Enable Slave Select Low Detect */
+ bool select_slave_low_detect_enable;
+# endif
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ /** Enable Master Slave Select */
+ bool master_slave_select_enable;
+# endif
+ /** Union for slave or master specific configuration */
+ union {
+ /** Slave specific configuration */
+ struct spi_slave_config slave;
+ /** Master specific configuration */
+ struct spi_master_config master;
+ } mode_specific;
+ /** GCLK generator to use as clock source */
+ enum gclk_generator generator_source;
+ /** PAD0 pinmux */
+ uint32_t pinmux_pad0;
+ /** PAD1 pinmux */
+ uint32_t pinmux_pad1;
+ /** PAD2 pinmux */
+ uint32_t pinmux_pad2;
+ /** PAD3 pinmux */
+ uint32_t pinmux_pad3;
+};
+
+/**
+ * \brief Determines if the SPI module is currently synchronizing to the bus.
+ *
+ * This function will check if the underlying hardware peripheral module is
+ * currently synchronizing across multiple clock domains to the hardware bus.
+ * This function can be used to delay further operations on the module until it
+ * is ready.
+ *
+ * \param[in] module SPI hardware module
+ *
+ * \return Synchronization status of the underlying hardware module.
+ * \retval true Module synchronization is ongoing
+ * \retval false Module synchronization is not ongoing
+ *
+ */
+static inline bool spi_is_syncing(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+# ifdef FEATURE_SPI_SYNC_SCHEME_VERSION_2
+ /* Return synchronization status */
+ return (spi_module->SYNCBUSY.reg);
+# else
+ /* Return synchronization status */
+ return (spi_module->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY);
+# endif
+}
+
+/**
+ * \name Driver Initialization and Configuration
+ * @{
+ */
+
+/**
+ * \brief Initializes an SPI configuration structure to default values
+ *
+ * This function will initialize a given SPI configuration structure to a set
+ * of known default values. This function should be called on any new
+ * instance of the configuration structures before being modified by the
+ * user application.
+ *
+ * The default configuration is as follows:
+ * \li Master mode enabled
+ * \li MSB of the data is transmitted first
+ * \li Transfer mode 0
+ * \li MUX Setting D
+ * \li Character size eight bits
+ * \li Not enabled in sleep mode
+ * \li Receiver enabled
+ * \li Baudrate 100000
+ * \li Default pinmux settings for all pads
+ * \li GCLK generator 0
+ *
+ * \param[out] config Configuration structure to initialize to default values
+ */
+static inline void spi_get_config_defaults(
+ struct spi_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(config);
+
+ /* Default configuration values */
+ config->mode = SPI_MODE_MASTER;
+ config->data_order = SPI_DATA_ORDER_MSB;
+ config->transfer_mode = SPI_TRANSFER_MODE_0;
+ config->mux_setting = SPI_SIGNAL_MUX_SETTING_D;
+ config->character_size = SPI_CHARACTER_SIZE_8BIT;
+ config->run_in_standby = false;
+ config->receiver_enable = true;
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ config->select_slave_low_detect_enable= true;
+# endif
+# ifdef FEATURE_SPI_HARDWARE_SLAVE_SELECT
+ config->master_slave_select_enable= false;
+# endif
+ config->generator_source = GCLK_GENERATOR_0;
+
+ /* Clear mode specific config */
+ memset(&(config->mode_specific), 0, sizeof(config->mode_specific));
+
+ /* Master config defaults */
+ config->mode_specific.master.baudrate = 100000;
+
+ /* pinmux config defaults */
+ config->pinmux_pad0 = PINMUX_DEFAULT;
+ config->pinmux_pad1 = PINMUX_DEFAULT;
+ config->pinmux_pad2 = PINMUX_DEFAULT;
+ config->pinmux_pad3 = PINMUX_DEFAULT;
+
+};
+
+/**
+ * \brief Initializes an SPI peripheral slave device configuration structure to default values
+ *
+ * This function will initialize a given SPI slave device configuration
+ * structure to a set of known default values. This function should be called
+ * on any new instance of the configuration structures before being modified by
+ * the user application.
+ *
+ * The default configuration is as follows:
+ * \li Slave Select on GPIO pin 10
+ * \li Addressing not enabled
+ *
+ * \param[out] config Configuration structure to initialize to default values
+ */
+static inline void spi_slave_inst_get_config_defaults(
+ struct spi_slave_inst_config *const config)
+{
+ Assert(config);
+
+ config->ss_pin = 10;
+ config->address_enabled = false;
+ config->address = 0;
+}
+
+/**
+ * \brief Attaches an SPI peripheral slave
+ *
+ * This function will initialize the software SPI peripheral slave, based on
+ * the values of the config struct. The slave can then be selected and
+ * optionally addressed by the \ref spi_select_slave function.
+ *
+ * \param[out] slave Pointer to the software slave instance struct
+ * \param[in] config Pointer to the config struct
+ *
+ */
+static inline void spi_attach_slave(
+ struct spi_slave_inst *const slave,
+ const struct spi_slave_inst_config *const config)
+{
+ Assert(slave);
+ Assert(config);
+
+ slave->ss_pin = config->ss_pin;
+ slave->address_enabled = config->address_enabled;
+ slave->address = config->address;
+
+ /* Get default config for pin */
+ struct port_config pin_conf;
+ port_get_config_defaults(&pin_conf);
+
+ /* Edit config to set the pin as output */
+ pin_conf.direction = PORT_PIN_DIR_OUTPUT;
+
+ /* Set config on Slave Select pin */
+ port_pin_set_config(slave->ss_pin, &pin_conf);
+ port_pin_set_output_level(slave->ss_pin, true);
+}
+
+enum status_code spi_init(
+ struct spi_module *const module,
+ Sercom *const hw,
+ const struct spi_config *const config);
+
+/** @} */
+
+/**
+ * \name Enable/Disable
+ * @{
+ */
+
+/**
+ * \brief Enables the SERCOM SPI module
+ *
+ * This function will enable the SERCOM SPI module.
+ *
+ * \param[in,out] module Pointer to the software instance struct
+ */
+static inline void spi_enable(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+# if SPI_CALLBACK_MODE == true
+ system_interrupt_enable(_sercom_get_interrupt_vector(module->hw));
+# endif
+
+ while (spi_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+
+ /* Enable SPI */
+ spi_module->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
+}
+
+/**
+ * \brief Disables the SERCOM SPI module
+ *
+ * This function will disable the SERCOM SPI module.
+ *
+ * \param[in,out] module Pointer to the software instance struct
+ */
+static inline void spi_disable(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+# if SPI_CALLBACK_MODE == true
+ system_interrupt_disable(_sercom_get_interrupt_vector(module->hw));
+# endif
+
+ while (spi_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+
+ /* Disbale interrupt */
+ spi_module->INTENCLR.reg = SERCOM_SPI_INTENCLR_MASK;
+ /* Clear interrupt flag */
+ spi_module->INTFLAG.reg = SERCOM_SPI_INTFLAG_MASK;
+
+ /* Disable SPI */
+ spi_module->CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE;
+}
+
+void spi_reset(
+ struct spi_module *const module);
+
+/** @} */
+
+enum status_code spi_set_baudrate(
+ struct spi_module *const module,
+ uint32_t baudrate);
+
+/**
+ * \name Lock/Unlock
+ * @{
+ */
+
+/**
+ * \brief Attempt to get lock on driver instance
+ *
+ * This function checks the instance's lock, which indicates whether or not it
+ * is currently in use, and sets the lock if it was not already set.
+ *
+ * The purpose of this is to enable exclusive access to driver instances, so
+ * that, e.g., transactions by different services will not interfere with each
+ * other.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline enum status_code spi_lock(struct spi_module *const module)
+{
+ enum status_code status;
+
+ system_interrupt_enter_critical_section();
+
+ if (module->locked) {
+ status = STATUS_BUSY;
+ } else {
+ module->locked = true;
+ status = STATUS_OK;
+ }
+
+ system_interrupt_leave_critical_section();
+
+ return status;
+}
+
+/**
+ * \brief Unlock driver instance
+ *
+ * This function clears the instance lock, indicating that it is available for
+ * use.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline void spi_unlock(struct spi_module *const module)
+{
+ module->locked = false;
+}
+
+/** @} */
+
+/**
+ * \name Ready to Write/Read
+ * @{
+ */
+
+ /**
+ * \brief Checks if the SPI in master mode has shifted out last data, or if the master has ended the transfer in slave mode.
+ *
+ * This function will check if the SPI master module has shifted out last data,
+ * or if the slave select pin has been drawn high by the master for the SPI
+ * slave module.
+ *
+ * \param[in] module Pointer to the software instance struct
+ *
+ * \return Indication of whether any writes are ongoing.
+ * \retval true If the SPI master module has shifted out data, or slave select
+ * has been drawn high for SPI slave
+ * \retval false If the SPI master module has not shifted out data
+ */
+static inline bool spi_is_write_complete(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Check interrupt flag */
+ return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC);
+}
+
+ /**
+ * \brief Checks if the SPI module is ready to write data
+ *
+ * This function will check if the SPI module is ready to write data.
+ *
+ * \param[in] module Pointer to the software instance struct
+ *
+ * \return Indication of whether the module is ready to read data or not.
+ * \retval true If the SPI module is ready to write data
+ * \retval false If the SPI module is not ready to write data
+ */
+static inline bool spi_is_ready_to_write(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Check interrupt flag */
+ return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE);
+}
+
+/**
+ * \brief Checks if the SPI module is ready to read data
+ *
+ * This function will check if the SPI module is ready to read data.
+ *
+ * \param[in] module Pointer to the software instance struct
+ *
+ * \return Indication of whether the module is ready to read data or not.
+ * \retval true If the SPI module is ready to read data
+ * \retval false If the SPI module is not ready to read data
+ */
+static inline bool spi_is_ready_to_read(
+ struct spi_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Check interrupt flag */
+ return (spi_module->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC);
+}
+/** @} */
+
+/**
+ * \name Read/Write
+ * @{
+ */
+
+ /**
+ * \brief Transfers a single SPI character
+ *
+ * This function will send a single SPI character via SPI and ignore any data
+ * shifted in by the connected device. To both send and receive data, use the
+ * \ref spi_transceive_wait function or use the \ref spi_read function after
+ * writing a character. The \ref spi_is_ready_to_write function
+ * should be called before calling this function.
+ *
+ * Note that this function does not handle the SS (Slave Select)
+ * pin(s) in master mode; this must be handled from the user application.
+ *
+ * \note In slave mode, the data will not be transferred before a master
+ * initiates a transaction.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] tx_data Data to transmit
+ *
+ * \return Status of the procedure.
+ * \retval STATUS_OK If the data was written
+ * \retval STATUS_BUSY If the last write was not completed
+ */
+static inline enum status_code spi_write(
+ struct spi_module *module,
+ uint16_t tx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Check if the data register has been copied to the shift register */
+ if (!spi_is_ready_to_write(module)) {
+ /* Data register has not been copied to the shift register, return */
+ return STATUS_BUSY;
+ }
+
+ /* Write the character to the DATA register */
+ spi_module->DATA.reg = tx_data & SERCOM_SPI_DATA_MASK;
+
+ return STATUS_OK;
+}
+
+enum status_code spi_write_buffer_wait(
+ struct spi_module *const module,
+ const uint8_t *tx_data,
+ uint16_t length);
+
+/**
+ * \brief Reads last received SPI character
+ *
+ * This function will return the last SPI character shifted into the receive
+ * register by the \ref spi_write function.
+ *
+ * \note The \ref spi_is_ready_to_read function should be called before calling
+ * this function.
+ *
+ * \note Receiver must be enabled in the configuration.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[out] rx_data Pointer to store the received data
+ *
+ * \returns Status of the read operation.
+ * \retval STATUS_OK If data was read
+ * \retval STATUS_ERR_IO If no data is available
+ * \retval STATUS_ERR_OVERFLOW If the data is overflown
+ */
+static inline enum status_code spi_read(
+ struct spi_module *const module,
+ uint16_t *rx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomSpi *const spi_module = &(module->hw->SPI);
+
+ /* Check if data is ready to be read */
+ if (!spi_is_ready_to_read(module)) {
+ /* No data has been received, return */
+ return STATUS_ERR_IO;
+ }
+
+ /* Return value */
+ enum status_code retval = STATUS_OK;
+
+ /* Check if data is overflown */
+ if (spi_module->STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) {
+ retval = STATUS_ERR_OVERFLOW;
+ /* Clear overflow flag */
+ spi_module->STATUS.reg = SERCOM_SPI_STATUS_BUFOVF;
+ }
+
+ /* Read the character from the DATA register */
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ *rx_data = (spi_module->DATA.reg & SERCOM_SPI_DATA_MASK);
+ } else {
+ *rx_data = (uint8_t)spi_module->DATA.reg;
+ }
+
+ return retval;
+}
+
+enum status_code spi_read_buffer_wait(
+ struct spi_module *const module,
+ uint8_t *rx_data,
+ uint16_t length,
+ uint16_t dummy);
+
+enum status_code spi_transceive_wait(
+ struct spi_module *const module,
+ uint16_t tx_data,
+ uint16_t *rx_data);
+
+enum status_code spi_transceive_buffer_wait(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint8_t *rx_data,
+ uint16_t length);
+
+enum status_code spi_select_slave(
+ struct spi_module *const module,
+ struct spi_slave_inst *const slave,
+ bool select);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+
+/**
+ * \page asfdoc_sam0_sercom_spi_extra Extra Information for SERCOM SPI Driver
+ *
+ * \section asfdoc_sam0_sercom_spi_extra_acronyms Acronyms
+ * Below is a table listing the acronyms used in this module, along with their
+ * intended meanings.
+ *
+ * <table>
+ * <tr>
+ * <th>Acronym</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td>SERCOM</td>
+ * <td>Serial Communication Interface</td>
+ * </tr>
+ * <tr>
+ * <td>SPI</td>
+ * <td>Serial Peripheral Interface</td>
+ * </tr>
+ * <tr>
+ * <td>SCK</td>
+ * <td>Serial Clock</td>
+ * </tr>
+ * <tr>
+ * <td>MOSI</td>
+ * <td>Master Output Slave Input</td>
+ * </tr>
+ * <tr>
+ * <td>MISO</td>
+ * <td>Master Input Slave Output</td>
+ * </tr>
+ * <tr>
+ * <td>SS</td>
+ * <td>Slave Select</td>
+ * </tr>
+ * <tr>
+ * <td>DIO</td>
+ * <td>Data Input Output</td>
+ * </tr>
+ * <tr>
+ * <td>DO</td>
+ * <td>Data Output</td>
+ * </tr>
+ * <tr>
+ * <td>DI</td>
+ * <td>Data Input</td>
+ * </tr>
+ * <tr>
+ * <td>DMA</td>
+ * <td>Direct Memory Access</td>
+ * </tr>
+ * </table>
+ *
+ * \section asfdoc_sam0_sercom_spi_extra_dependencies Dependencies
+ * The SPI driver has the following dependencies:
+ * \li \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_extra_workarounds Workarounds Implemented by Driver
+ * No workarounds in driver.
+ *
+ * \section asfdoc_sam0_sercom_spi_extra_history Module History
+ * An overview of the module history is presented in the table below, with
+ * details on the enhancements and fixes made to the module since its first
+ * release. The current version of this corresponds to the newest version in the table.
+ *
+ * <table>
+ * <tr>
+ * <th>Changelog</th>
+ * </tr>
+ * <tr>
+ * <td>Added new features as below:
+ * \li Slave select low detect
+ * \li Hardware slave select
+ * \li DMA support </td>
+ * </tr>
+ * <tr>
+ * <td>Edited slave part of write and transceive buffer functions to ensure
+ * that second character is sent at the right time</td>
+ * </tr>
+ * <tr>
+ * <td>Renamed the anonymous union in \c struct spi_config to
+ * \c mode_specific</td>
+ * </tr>
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * </table>
+ */
+
+/**
+ * \page asfdoc_sam0_sercom_spi_exqsg Examples for SERCOM SPI Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_sercom_spi_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that a QSG can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * - \subpage asfdoc_sam0_sercom_spi_master_basic_use
+ * - \subpage asfdoc_sam0_sercom_spi_slave_basic_use
+ * \if SPI_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_sercom_spi_master_callback_use
+ * - \subpage asfdoc_sam0_sercom_spi_slave_callback_use
+ * \endif
+ * - \subpage asfdoc_sam0_sercom_spi_dma_use_case
+ */
+
+ /**
+ * \page asfdoc_sam0_sercom_spi_mux_settings MUX Settings
+ *
+ * The following lists the possible internal SERCOM module pad function
+ * assignments for the four SERCOM pads in both SPI Master and SPI Slave
+ * modes. They are combinations of DOPO and DIPO in CTRLA.
+ * Note that this is in addition to the physical GPIO pin MUX of the device,
+ * and can be used in conjunction to optimize the serial data pin-out.
+ *
+ * \section asfdoc_sam0_sercom_spi_mux_settings_master Master Mode Settings
+ * The following table describes the SERCOM pin functionalities for the various
+ * MUX settings, whilst in SPI Master mode.
+ *
+ * \note If MISO is unlisted, the SPI receiver must not be enabled for the
+ * given MUX setting.
+ *
+ * <table>
+ * <tr>
+ * <th>Combination</th>
+ * <th>DOPO / DIPO</th>
+ * <th>SERCOM PAD[0]</th>
+ * <th>SERCOM PAD[1]</th>
+ * <th>SERCOM PAD[2]</th>
+ * <th>SERCOM PAD[3]</th>
+ * </tr>
+ * <tr>
+ * <td>A</td>
+ * <td>0x0 / 0x0</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>B</td>
+ * <td>0x0 / 0x1</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>C</td>
+ * <td>0x0 / 0x2</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * <td>MISO</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>D</td>
+ * <td>0x0 / 0x3</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * <td>-</td>
+ * <td>MISO</td>
+ * </tr>
+ * <tr>
+ * <td>E</td>
+ * <td>0x1 / 0x0</td>
+ * <td>MISO</td>
+ * <td>-</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>F</td>
+ * <td>0x1 / 0x1</td>
+ * <td>-</td>
+ * <td>MISO</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>G</td>
+ * <td>0x1 / 0x2</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>H</td>
+ * <td>0x1 / 0x3</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>I</td>
+ * <td>0x2 / 0x0</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * <td>-</td>
+ * <td>MOSI</td>
+ * </tr>
+ * <tr>
+ * <td>J</td>
+ * <td>0x2 / 0x1</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * <td>-</td>
+ * <td>MOSI</td>
+ * </tr>
+ * <tr>
+ * <td>K</td>
+ * <td>0x2 / 0x2</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * <td>MISO</td>
+ * <td>MOSI</td>
+ * </tr>
+ * <tr>
+ * <td>L</td>
+ * <td>0x2 / 0x3</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * <td>-</td>
+ * <td>MOSI</td>
+ * </tr>
+ * <tr>
+ * <td>M</td>
+ * <td>0x3 / 0x0</td>
+ * <td>MOSI</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>N</td>
+ * <td>0x3 / 0x1</td>
+ * <td>MOSI</td>
+ * <td>MISO</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>O</td>
+ * <td>0x3 / 0x2</td>
+ * <td>MOSI</td>
+ * <td>-</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>P</td>
+ * <td>0x3 / 0x3</td>
+ * <td>MOSI</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_mux_settings_slave Slave Mode Settings
+ * The following table describes the SERCOM pin functionalities for the various
+ * MUX settings, whilst in SPI Slave mode.
+ *
+ * \note If MISO is unlisted, the SPI receiver must not be enabled for the
+ * given MUX setting.
+ *
+ * <table>
+ * <tr>
+ * <th>Combination</th>
+ * <th>DOPO / DIPO</th>
+ * <th>SERCOM PAD[0]</th>
+ * <th>SERCOM PAD[1]</th>
+ * <th>SERCOM PAD[2]</th>
+ * <th>SERCOM PAD[3]</th>
+ * </tr>
+ * <tr>
+ * <td>A</td>
+ * <td>0x0 / 0x0</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>B</td>
+ * <td>0x0 / 0x1</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>C</td>
+ * <td>0x0 / 0x2</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>D</td>
+ * <td>0x0 / 0x3</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>MOSI</td>
+ * </tr>
+ * <tr>
+ * <td>E</td>
+ * <td>0x1 / 0x0</td>
+ * <td>MOSI</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>F</td>
+ * <td>0x1 / 0x1</td>
+ * <td>-</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>G</td>
+ * <td>0x1 / 0x2</td>
+ * <td>-</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>H</td>
+ * <td>0x1 / 0x3</td>
+ * <td>-</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>I</td>
+ * <td>0x2 / 0x0</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * </tr>
+ * <tr>
+ * <td>J</td>
+ * <td>0x2 / 0x1</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * </tr>
+ * <tr>
+ * <td>K</td>
+ * <td>0x2 / 0x2</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * </tr>
+ * <tr>
+ * <td>L</td>
+ * <td>0x2 / 0x3</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * <td>/SS</td>
+ * <td>MISO</td>
+ * </tr>
+ * <tr>
+ * <td>M</td>
+ * <td>0x3 / 0x0</td>
+ * <td>MISO</td>
+ * <td>/SS</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>N</td>
+ * <td>0x3 / 0x1</td>
+ * <td>MISO</td>
+ * <td>/SS</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>O</td>
+ * <td>0x3 / 0x2</td>
+ * <td>MISO</td>
+ * <td>/SS</td>
+ * <td>MOSI</td>
+ * <td>SCK</td>
+ * </tr>
+ * <tr>
+ * <td>P</td>
+ * <td>0x3 / 0x3</td>
+ * <td>MISO</td>
+ * <td>/SS</td>
+ * <td>-</td>
+ * <td>SCK</td>
+ * </tr>
+ * </table>
+ *
+ *
+ *
+ * \page asfdoc_sam0_sercom_spi_document_revision_history Document Revision History
+ *
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</th>
+ * <th>Date</th>
+ * <th>Comments</th>
+ * </tr>
+ * <tr>
+ * <td>42115E</td>
+ * <td>12/2015</td>
+ * <td>Add SAM L21/L22, SAM DA1, SAM D09, SAMR30 and SAM C21 support</td>
+ * </tr>
+ * <tr>
+ * <td>42115D</td>
+ * <td>12/2014</td>
+ * <td>Add SAM R21/D10/D11 support</td>
+ * </tr>
+ * <tr>
+ * <td>42115C</td>
+ * <td>01/2014</td>
+ * <td>Add SAM D21 support</td>
+ * </tr>
+ * <tr>
+ * <td>42115B</td>
+ * <td>11/2013</td>
+ * <td>Replaced the pad multiplexing documentation with a condensed table</td>
+ * </tr>
+ * <tr>
+ * <td>42115A</td>
+ * <td>06/2013</td>
+ * <td>Initial release</td>
+ * </tr>
+ * </table>
+ */
+
+#endif /* SPI_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.c
new file mode 100644
index 000000000..5909843b2
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.c
@@ -0,0 +1,741 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver
+ *
+ * Copyright (c) 2013-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include "spi_interrupt.h"
+
+/**
+ * \internal
+ *
+ * Dummy byte to send when reading in master mode.
+ */
+uint16_t dummy_write;
+
+/**
+ * \internal
+ * Starts transceive of buffers with a given length
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] rx_data Pointer to data to be received
+ * \param[in] tx_data Pointer to data to be transmitted
+ * \param[in] length Length of data buffer
+ *
+ */
+static void _spi_transceive_buffer(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ Assert(module);
+ Assert(tx_data);
+
+ /* Write parameters to the device instance */
+ module->remaining_tx_buffer_length = length;
+ module->remaining_rx_buffer_length = length;
+ module->rx_buffer_ptr = rx_data;
+ module->tx_buffer_ptr = tx_data;
+ module->status = STATUS_BUSY;
+
+ module->dir = SPI_DIRECTION_BOTH;
+
+ /* Get a pointer to the hardware module instance */
+ SercomSpi *const hw = &(module->hw->SPI);
+
+ /* Enable the Data Register Empty and RX Complete Interrupt */
+ hw->INTENSET.reg = (SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY |
+ SPI_INTERRUPT_FLAG_RX_COMPLETE);
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (module->mode == SPI_MODE_SLAVE) {
+ /* Clear TXC flag if set */
+ hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ /* Enable transmit complete interrupt for slave */
+ hw->INTENSET.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ }
+# endif
+}
+
+/**
+ * \internal
+ * Starts write of a buffer with a given length
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] tx_data Pointer to data to be transmitted
+ * \param[in] length Length of data buffer
+ *
+ */
+static void _spi_write_buffer(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint16_t length)
+{
+ Assert(module);
+ Assert(tx_data);
+
+ /* Write parameters to the device instance */
+ module->remaining_tx_buffer_length = length;
+ module->remaining_dummy_buffer_length = length;
+ module->tx_buffer_ptr = tx_data;
+ module->status = STATUS_BUSY;
+
+ module->dir = SPI_DIRECTION_WRITE;
+
+ /* Get a pointer to the hardware module instance */
+ SercomSpi *const hw = &(module->hw->SPI);
+
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (module->mode == SPI_MODE_SLAVE) {
+ /* Clear TXC flag if set */
+ hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ /* Enable transmit complete interrupt for slave */
+ hw->INTENSET.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ }
+# endif
+
+ if (module->receiver_enabled) {
+ /* Enable the Data Register Empty and RX Complete interrupt */
+ hw->INTENSET.reg = (SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY |
+ SPI_INTERRUPT_FLAG_RX_COMPLETE);
+ } else {
+ /* Enable the Data Register Empty interrupt */
+ hw->INTENSET.reg = SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY;
+ }
+}
+
+/**
+ * \internal
+ * Setup SPI to read a buffer with a given length
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] rx_data Pointer to data to be received
+ * \param[in] length Length of data buffer
+ *
+ */
+static void _spi_read_buffer(
+ struct spi_module *const module,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ Assert(module);
+ Assert(rx_data);
+
+ uint8_t tmp_intenset = 0;
+
+ /* Set length for the buffer and the pointer, and let
+ * the interrupt handler do the rest */
+ module->remaining_rx_buffer_length = length;
+ module->remaining_dummy_buffer_length = length;
+ module->rx_buffer_ptr = rx_data;
+ module->status = STATUS_BUSY;
+
+ module->dir = SPI_DIRECTION_READ;
+
+ /* Get a pointer to the hardware module instance */
+ SercomSpi *const hw = &(module->hw->SPI);
+
+ /* Enable the RX Complete Interrupt */
+ tmp_intenset = SPI_INTERRUPT_FLAG_RX_COMPLETE;
+
+# if CONF_SPI_MASTER_ENABLE == true
+ if (module->mode == SPI_MODE_MASTER && module->dir == SPI_DIRECTION_READ) {
+ /* Enable Data Register Empty interrupt for master */
+ tmp_intenset |= SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY;
+ }
+# endif
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (module->mode == SPI_MODE_SLAVE) {
+ /* Clear TXC flag if set */
+ hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ /* Enable transmit complete interrupt for slave */
+ tmp_intenset |= SPI_INTERRUPT_FLAG_TX_COMPLETE;
+
+ /* Workaround for SSL flag enable */
+#ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+ /* Clear SSL flag if set */
+ hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW;
+ /* Enable Slave Select Low Interrupt for slave */
+ tmp_intenset |= SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW;
+#endif
+ }
+# endif
+
+ /* Enable all interrupts simultaneously */
+ hw->INTENSET.reg = tmp_intenset;
+}
+
+/**
+ * \brief Registers a SPI callback function
+ *
+ * Registers a callback function which is implemented by the user.
+ *
+ * \note The callback must be enabled by \ref spi_enable_callback, in order
+ * for the interrupt handler to call it when the conditions for the
+ * callback type are met.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] callback_func Pointer to callback function
+ * \param[in] callback_type Callback type given by an enum
+ *
+ */
+void spi_register_callback(
+ struct spi_module *const module,
+ spi_callback_t callback_func,
+ enum spi_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(callback_func);
+
+ /* Register callback function */
+ module->callback[callback_type] = callback_func;
+
+ /* Set the bit corresponding to the callback_type */
+ module->registered_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters a SPI callback function
+ *
+ * Unregisters a callback function which is implemented by the user.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ *
+ */
+void spi_unregister_callback(
+ struct spi_module *const module,
+ enum spi_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Unregister callback function */
+ module->callback[callback_type] = NULL;
+
+ /* Clear the bit corresponding to the callback_type */
+ module->registered_callback &= ~(1 << callback_type);
+}
+
+/**
+ * \brief Asynchronous buffer write
+ *
+ * Sets up the driver to write to the SPI from a given buffer. If registered
+ * and enabled, a callback function will be called when the write is finished.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[out] tx_data Pointer to data buffer to receive
+ * \param[in] length Data buffer length
+ *
+ * \returns Status of the write request operation.
+ * \retval STATUS_OK If the operation completed successfully
+ * \retval STATUS_ERR_BUSY If the SPI was already busy with a write
+ * operation
+ * \retval STATUS_ERR_INVALID_ARG If requested write length was zero
+ */
+enum status_code spi_write_buffer_job(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint16_t length)
+{
+ Assert(module);
+ Assert(tx_data);
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ /* Check if the SPI is busy transmitting or slave waiting for TXC*/
+ if (module->status == STATUS_BUSY) {
+ return STATUS_BUSY;
+ }
+
+ /* Issue internal write */
+ _spi_write_buffer(module, tx_data, length);
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Asynchronous buffer read
+ *
+ * Sets up the driver to read from the SPI to a given buffer. If registered
+ * and enabled, a callback function will be called when the read is finished.
+ *
+ * \note If address matching is enabled for the slave, the first character
+ * received and placed in the RX buffer will be the address.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[out] rx_data Pointer to data buffer to receive
+ * \param[in] length Data buffer length
+ * \param[in] dummy Dummy character to send when reading in master mode
+ *
+ * \returns Status of the operation.
+ * \retval STATUS_OK If the operation completed successfully
+ * \retval STATUS_ERR_BUSY If the SPI was already busy with a read
+ * operation
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ * \retval STATUS_ERR_INVALID_ARG If requested read length was zero
+ */
+enum status_code spi_read_buffer_job(
+ struct spi_module *const module,
+ uint8_t *rx_data,
+ uint16_t length,
+ uint16_t dummy)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(rx_data);
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if the SPI is busy transmitting or slave waiting for TXC*/
+ if (module->status == STATUS_BUSY) {
+ return STATUS_BUSY;
+ }
+
+ dummy_write = dummy;
+ /* Issue internal read */
+ _spi_read_buffer(module, rx_data, length);
+ return STATUS_OK;
+}
+
+/**
+ * \brief Asynchronous buffer write and read
+ *
+ * Sets up the driver to write and read to and from given buffers. If registered
+ * and enabled, a callback function will be called when the transfer is finished.
+ *
+ * \note If address matching is enabled for the slave, the first character
+ * received and placed in the RX buffer will be the address.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] tx_data Pointer to data buffer to send
+ * \param[out] rx_data Pointer to data buffer to receive
+ * \param[in] length Data buffer length
+ *
+ * \returns Status of the operation.
+ * \retval STATUS_OK If the operation completed successfully
+ * \retval STATUS_ERR_BUSY If the SPI was already busy with a read
+ * operation
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ * \retval STATUS_ERR_INVALID_ARG If requested read length was zero
+ */
+enum status_code spi_transceive_buffer_job(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(rx_data);
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Check if the SPI is busy transmitting or slave waiting for TXC*/
+ if (module->status == STATUS_BUSY) {
+ return STATUS_BUSY;
+ }
+
+ /* Issue internal transceive */
+ _spi_transceive_buffer(module, tx_data, rx_data, length);
+
+ return STATUS_OK;
+}
+/**
+ * \brief Aborts an ongoing job
+ *
+ * This function will abort the specified job type.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ */
+void spi_abort_job(
+ struct spi_module *const module)
+{
+ /* Pointer to the hardware module instance */
+ SercomSpi *const spi_hw
+ = &(module->hw->SPI);
+
+ /* Abort ongoing job */
+
+ /* Disable interrupts */
+ spi_hw->INTENCLR.reg = SPI_INTERRUPT_FLAG_RX_COMPLETE |
+ SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY |
+ SPI_INTERRUPT_FLAG_TX_COMPLETE;
+
+ module->status = STATUS_ABORTED;
+ module->remaining_rx_buffer_length = 0;
+ module->remaining_dummy_buffer_length = 0;
+ module->remaining_tx_buffer_length = 0;
+
+ module->dir = SPI_DIRECTION_IDLE;
+}
+
+# if CONF_SPI_SLAVE_ENABLE == true || CONF_SPI_MASTER_ENABLE == true
+/**
+ * \internal
+ * Writes a character from the TX buffer to the Data register.
+ *
+ * \param[in,out] module Pointer to SPI software instance struct
+ */
+static void _spi_write(
+ struct spi_module *const module)
+{
+ /* Pointer to the hardware module instance */
+ SercomSpi *const spi_hw = &(module->hw->SPI);
+
+ /* Write value will be at least 8-bits long */
+ uint16_t data_to_send = *(module->tx_buffer_ptr);
+ /* Increment 8-bit pointer */
+ (module->tx_buffer_ptr)++;
+
+ if (module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ data_to_send |= ((*(module->tx_buffer_ptr)) << 8);
+ /* Increment 8-bit pointer */
+ (module->tx_buffer_ptr)++;
+ }
+
+ /* Write the data to send*/
+ spi_hw->DATA.reg = data_to_send & SERCOM_SPI_DATA_MASK;
+
+ /* Decrement remaining buffer length */
+ (module->remaining_tx_buffer_length)--;
+}
+# endif
+
+# if CONF_SPI_MASTER_ENABLE == true
+/**
+ * \internal
+ * Writes a dummy character to the Data register.
+ *
+ * \param[in,out] module Pointer to SPI software instance struct
+ */
+static void _spi_write_dummy(
+ struct spi_module *const module)
+{
+ /* Pointer to the hardware module instance */
+ SercomSpi *const spi_hw = &(module->hw->SPI);
+
+ /* Write dummy byte */
+ spi_hw->DATA.reg = dummy_write;
+
+ /* Decrement remaining dummy buffer length */
+ module->remaining_dummy_buffer_length--;
+}
+# endif
+
+/**
+ * \internal
+ * Writes a dummy character from the to the Data register.
+ *
+ * \param[in,out] module Pointer to SPI software instance struct
+ */
+static void _spi_read_dummy(
+ struct spi_module *const module)
+{
+ /* Pointer to the hardware module instance */
+ SercomSpi *const spi_hw = &(module->hw->SPI);
+ uint16_t flush = 0;
+
+ /* Read dummy byte */
+ flush = spi_hw->DATA.reg;
+ UNUSED(flush);
+
+ /* Decrement remaining dummy buffer length */
+ module->remaining_dummy_buffer_length--;
+}
+
+/**
+ * \internal
+ * Reads a character from the Data register to the RX buffer.
+ *
+ * \param[in,out] module Pointer to SPI software instance struct
+ */
+static void _spi_read(
+ struct spi_module *const module)
+{
+ /* Pointer to the hardware module instance */
+ SercomSpi *const spi_hw = &(module->hw->SPI);
+
+ uint16_t received_data = (spi_hw->DATA.reg & SERCOM_SPI_DATA_MASK);
+
+ /* Read value will be at least 8-bits long */
+ *(module->rx_buffer_ptr) = received_data;
+ /* Increment 8-bit pointer */
+ module->rx_buffer_ptr += 1;
+
+ if(module->character_size == SPI_CHARACTER_SIZE_9BIT) {
+ /* 9-bit data, write next received byte to the buffer */
+ *(module->rx_buffer_ptr) = (received_data >> 8);
+ /* Increment 8-bit pointer */
+ module->rx_buffer_ptr += 1;
+ }
+
+ /* Decrement length of the remaining buffer */
+ module->remaining_rx_buffer_length--;
+}
+
+/**
+ * \internal
+ *
+ * Handles interrupts as they occur, and it will run callback functions
+ * which are registered and enabled.
+ *
+ * \note This function will be called by the Sercom_Handler, and should
+ * not be called directly from any application code.
+ *
+ * \param[in] instance ID of the SERCOM instance calling the interrupt
+ * handler.
+ */
+void _spi_interrupt_handler(
+ uint8_t instance)
+{
+ /* Get device instance from the look-up table */
+ struct spi_module *module
+ = (struct spi_module *)_sercom_instances[instance];
+
+ /* Pointer to the hardware module instance */
+ SercomSpi *const spi_hw = &(module->hw->SPI);
+
+ /* Combine callback registered and enabled masks. */
+ uint8_t callback_mask =
+ module->enabled_callback & module->registered_callback;
+
+ /* Read and mask interrupt flag register */
+ uint16_t interrupt_status = spi_hw->INTFLAG.reg;
+ interrupt_status &= spi_hw->INTENSET.reg;
+
+ /* Data register empty interrupt */
+ if (interrupt_status & SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY) {
+# if CONF_SPI_MASTER_ENABLE == true
+ if ((module->mode == SPI_MODE_MASTER) &&
+ (module->dir == SPI_DIRECTION_READ)) {
+ /* Send dummy byte when reading in master mode */
+ _spi_write_dummy(module);
+ if (module->remaining_dummy_buffer_length == 0) {
+ /* Disable the Data Register Empty Interrupt */
+ spi_hw->INTENCLR.reg
+ = SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY;
+ }
+ }
+# endif
+
+ if (0
+# if CONF_SPI_MASTER_ENABLE == true
+ || ((module->mode == SPI_MODE_MASTER) &&
+ (module->dir != SPI_DIRECTION_READ))
+# endif
+# if CONF_SPI_SLAVE_ENABLE == true
+ || ((module->mode == SPI_MODE_SLAVE) &&
+ (module->dir != SPI_DIRECTION_READ))
+# endif
+ ) {
+ /* Write next byte from buffer */
+ _spi_write(module);
+ if (module->remaining_tx_buffer_length == 0) {
+ /* Disable the Data Register Empty Interrupt */
+ spi_hw->INTENCLR.reg
+ = SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY;
+
+ if (module->dir == SPI_DIRECTION_WRITE &&
+ !(module->receiver_enabled)) {
+ /* Enable the Data Register transmit complete Interrupt */
+ spi_hw->INTENSET.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ }
+ }
+ }
+ }
+
+ /* Receive complete interrupt*/
+ if (interrupt_status & SPI_INTERRUPT_FLAG_RX_COMPLETE) {
+ /* Check for overflow */
+ if (spi_hw->STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) {
+ if (module->dir != SPI_DIRECTION_WRITE) {
+ /* Store the error code */
+ module->status = STATUS_ERR_OVERFLOW;
+
+ /* End transaction */
+ module->dir = SPI_DIRECTION_IDLE;
+
+ spi_hw->INTENCLR.reg = SPI_INTERRUPT_FLAG_RX_COMPLETE |
+ SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY;
+ /* Run callback if registered and enabled */
+ if (callback_mask & (1 << SPI_CALLBACK_ERROR)) {
+ (module->callback[SPI_CALLBACK_ERROR])(module);
+ }
+ }
+ /* Flush */
+ uint16_t flush = spi_hw->DATA.reg;
+ UNUSED(flush);
+ /* Clear overflow flag */
+ spi_hw->STATUS.reg = SERCOM_SPI_STATUS_BUFOVF;
+ } else {
+ if (module->dir == SPI_DIRECTION_WRITE) {
+ /* Flush receive buffer when writing */
+ _spi_read_dummy(module);
+ if (module->remaining_dummy_buffer_length == 0) {
+ spi_hw->INTENCLR.reg = SPI_INTERRUPT_FLAG_RX_COMPLETE;
+ module->status = STATUS_OK;
+ module->dir = SPI_DIRECTION_IDLE;
+ /* Run callback if registered and enabled */
+ if (callback_mask &
+ (1 << SPI_CALLBACK_BUFFER_TRANSMITTED)){
+ (module->callback[SPI_CALLBACK_BUFFER_TRANSMITTED])(module);
+ }
+ }
+ } else {
+ /* Read data register */
+ _spi_read(module);
+
+ /* Check if the last character have been received */
+ if (module->remaining_rx_buffer_length == 0) {
+ module->status = STATUS_OK;
+ /* Disable RX Complete Interrupt and set status */
+ spi_hw->INTENCLR.reg = SPI_INTERRUPT_FLAG_RX_COMPLETE;
+ if(module->dir == SPI_DIRECTION_BOTH) {
+ if (callback_mask & (1 << SPI_CALLBACK_BUFFER_TRANSCEIVED)) {
+ (module->callback[SPI_CALLBACK_BUFFER_TRANSCEIVED])(module);
+ }
+ } else if (module->dir == SPI_DIRECTION_READ) {
+ if (callback_mask & (1 << SPI_CALLBACK_BUFFER_RECEIVED)) {
+ (module->callback[SPI_CALLBACK_BUFFER_RECEIVED])(module);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Transmit complete */
+ if (interrupt_status & SPI_INTERRUPT_FLAG_TX_COMPLETE) {
+# if CONF_SPI_SLAVE_ENABLE == true
+ if (module->mode == SPI_MODE_SLAVE) {
+ /* Transaction ended by master */
+
+ /* Disable interrupts */
+ spi_hw->INTENCLR.reg =
+ SPI_INTERRUPT_FLAG_TX_COMPLETE |
+ SPI_INTERRUPT_FLAG_RX_COMPLETE |
+ SPI_INTERRUPT_FLAG_DATA_REGISTER_EMPTY;
+ /* Clear interrupt flag */
+ spi_hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+
+
+ /* Reset all status information */
+ module->dir = SPI_DIRECTION_IDLE;
+ module->remaining_tx_buffer_length = 0;
+ module->remaining_rx_buffer_length = 0;
+ module->status = STATUS_OK;
+
+ if (callback_mask &
+ (1 << SPI_CALLBACK_SLAVE_TRANSMISSION_COMPLETE)) {
+ (module->callback[SPI_CALLBACK_SLAVE_TRANSMISSION_COMPLETE])
+ (module);
+ }
+
+ }
+# endif
+# if CONF_SPI_MASTER_ENABLE == true
+ if ((module->mode == SPI_MODE_MASTER) &&
+ (module->dir == SPI_DIRECTION_WRITE) && !(module->receiver_enabled)) {
+ /* Clear interrupt flag */
+ spi_hw->INTENCLR.reg
+ = SPI_INTERRUPT_FLAG_TX_COMPLETE;
+ /* Buffer sent with receiver disabled */
+ module->dir = SPI_DIRECTION_IDLE;
+ module->status = STATUS_OK;
+ /* Run callback if registered and enabled */
+ if (callback_mask & (1 << SPI_CALLBACK_BUFFER_TRANSMITTED)){
+ (module->callback[SPI_CALLBACK_BUFFER_TRANSMITTED])
+ (module);
+ }
+ }
+#endif
+ }
+
+# ifdef FEATURE_SPI_SLAVE_SELECT_LOW_DETECT
+# if CONF_SPI_SLAVE_ENABLE == true
+ /* When a high to low transition is detected on the _SS pin in slave mode */
+ if (interrupt_status & SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW) {
+ if (module->mode == SPI_MODE_SLAVE) {
+ /* Disable interrupts */
+ spi_hw->INTENCLR.reg = SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW;
+ /* Clear interrupt flag */
+ spi_hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_SLAVE_SELECT_LOW;
+
+ if (callback_mask & (1 << SPI_CALLBACK_SLAVE_SELECT_LOW)) {
+ (module->callback[SPI_CALLBACK_SLAVE_SELECT_LOW])(module);
+ }
+ }
+ }
+# endif
+# endif
+
+# ifdef FEATURE_SPI_ERROR_INTERRUPT
+ /* When combined error happen */
+ if (interrupt_status & SPI_INTERRUPT_FLAG_COMBINED_ERROR) {
+ /* Disable interrupts */
+ spi_hw->INTENCLR.reg = SPI_INTERRUPT_FLAG_COMBINED_ERROR;
+ /* Clear interrupt flag */
+ spi_hw->INTFLAG.reg = SPI_INTERRUPT_FLAG_COMBINED_ERROR;
+
+ if (callback_mask & (1 << SPI_CALLBACK_COMBINED_ERROR)) {
+ (module->callback[SPI_CALLBACK_COMBINED_ERROR])(module);
+ }
+ }
+# endif
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.h b/atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.h
new file mode 100644
index 000000000..bb7168250
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi/spi_interrupt.h
@@ -0,0 +1,190 @@
+/**
+ * \file
+ *
+ * \brief SAM Serial Peripheral Interface Driver (Callback Mode)
+ *
+ * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SPI_INTERRUPT_H_INCLUDED
+#define SPI_INTERRUPT_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_spi_group
+ *
+ * @{
+ */
+
+#include "spi.h"
+
+/**
+ * \name Callback Management
+ * @{
+ */
+
+void spi_register_callback(
+ struct spi_module *const module,
+ spi_callback_t callback_func,
+ enum spi_callback callback_type);
+
+void spi_unregister_callback(
+ struct spi_module *module,
+ enum spi_callback callback_type);
+
+/**
+ * \brief Enables an SPI callback of a given type
+ *
+ * Enables the callback function registered by the \ref spi_register_callback.
+ * The callback function will be called from the interrupt handler when the
+ * conditions for the callback type are met.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+static inline void spi_enable_callback(
+ struct spi_module *const module,
+ enum spi_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Enable callback */
+ module->enabled_callback |= (1 << callback_type);
+}
+
+/**
+ * \brief Disables callback
+ *
+ * Disables the callback function registered by the \ref spi_register_callback,
+ * and the callback will not be called from the interrupt routine.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+static inline void spi_disable_callback(
+ struct spi_module *const module,
+ enum spi_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Disable callback */
+ module->enabled_callback &= ~(1 << callback_type);
+}
+
+/** @} */
+
+
+/**
+ * \name Writing and Reading
+ * @{
+ */
+enum status_code spi_write_buffer_job(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint16_t length);
+
+enum status_code spi_read_buffer_job(
+ struct spi_module *const module,
+ uint8_t *rx_data,
+ uint16_t length,
+ uint16_t dummy);
+
+enum status_code spi_transceive_buffer_job(
+ struct spi_module *const module,
+ uint8_t *tx_data,
+ uint8_t *rx_data,
+ uint16_t length);
+
+void spi_abort_job(
+ struct spi_module *const module);
+
+/**
+ * \brief Retrieves the current status of a job.
+ *
+ * Retrieves the current status of a job that was previously issued.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ *
+ * \return Current job status.
+ */
+static inline enum status_code spi_get_job_status(
+ const struct spi_module *const module)
+{
+ return module->status;
+}
+
+/**
+ * \brief Retrieves the status of job once it ends.
+ *
+ * Waits for current job status to become non-busy, then returns its value.
+ *
+ * \param[in] module Pointer to SPI software instance struct
+ *
+ * \return Current non-busy job status.
+ */
+static inline enum status_code spi_get_job_status_wait(
+ const struct spi_module *const module)
+{
+ enum status_code status;
+
+ do {
+ status = spi_get_job_status(module);
+ } while (status == STATUS_BUSY);
+
+ return status;
+}
+
+/** @} */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPI_INTERRUPT_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi.h b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi.h
new file mode 100644
index 000000000..3bb66ff5b
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi.h
@@ -0,0 +1,55 @@
+/**
+ * \file
+ *
+ * \brief common SPI configuration
+ *
+ * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+
+#ifndef CONF_SPI_H_INCLUDED
+# define CONF_SPI_H_INCLUDED
+
+# define CONF_SPI_MASTER_ENABLE true
+# define CONF_SPI_SLAVE_ENABLE false
+
+#endif /* CONF_SPI_H_INCLUDED */
+
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi_master_vec.h b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi_master_vec.h
new file mode 100644
index 000000000..394b1fa61
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/module-config/conf_spi_master_vec.h
@@ -0,0 +1,68 @@
+/**
+ * \file
+ *
+ * \brief SERCOM SPI master with vectored I/O driver configuration
+ *
+ * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef CONF_SPI_MASTER_VEC_H
+#define CONF_SPI_MASTER_VEC_H
+
+#if defined(__FREERTOS__) || defined(__DOXYGEN__)
+# include <FreeRTOS.h>
+# include <semphr.h>
+
+# define CONF_SPI_MASTER_VEC_OS_SUPPORT
+# define CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE xSemaphoreHandle
+# define CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE(semaphore) \
+ vSemaphoreCreateBinary(semaphore)
+# define CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE(semaphore) \
+ vSemaphoreDelete(semaphore)
+# define CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE(semaphore) \
+ xSemaphoreTake((semaphore), portMAX_DELAY)
+# define CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE(semaphore) \
+ xSemaphoreGive((semaphore))
+# define CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR(semaphore) \
+ xSemaphoreGiveFromISR((semaphore), NULL)
+#endif
+
+#endif // CONF_SPI_MASTER_VEC_H \ No newline at end of file
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c
new file mode 100644
index 000000000..89de7dd0d
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.c
@@ -0,0 +1,588 @@
+/**
+ * \file
+ *
+ * \brief SERCOM SPI master with vectored I/O driver implementation
+ *
+ * Copyright (C) 2013-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "spi_master_vec.h"
+#include <sercom_interrupt.h>
+#include <system.h>
+#include <system_interrupt.h>
+
+/**
+ * \ingroup asfdoc_sam0_sercom_spi_master_vec_group
+ *
+ * @{
+ */
+
+/**
+ * \name Internal functions
+ * @{
+ */
+
+/** \cond INTERNAL */
+
+static void _spi_master_vec_int_handler(uint8_t sercom_index);
+
+/**
+ * \brief Wait for SERCOM SPI to synchronize
+ *
+ * \param[in] sercom_spi SERCOM SPI to check for synchronization.
+ *
+ * \note The implementation of this function depends on the SERCOM revision.
+ */
+static inline void _spi_master_vec_wait_for_sync(SercomSpi *const sercom_spi)
+{
+#if defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_1)
+ while (sercom_spi->STATUS.reg & SERCOM_SPI_STATUS_SYNCBUSY) {
+ /* Intentionally left empty */
+ }
+#elif defined(FEATURE_SERCOM_SYNCBUSY_SCHEME_VERSION_2)
+ while (sercom_spi->SYNCBUSY.reg) {
+ /* Intentionally left empty */
+ }
+#else
+# error Unknown SERCOM SYNCBUSY scheme!
+#endif
+}
+
+/**
+ * \brief Pin MUX configuration helper
+ *
+ * \param[in] pinmux Pin MUX setting to apply. Special values:
+ * \arg \c PINMUX_UNUSED to do nothing.
+ * \arg \c PINMUX_DEFAULT to use default pin MUX for the SERCOM pad.
+ * \param[in] sercom,padnum SERCOM pad specification, for \ref PINMUX_DEFAULT.
+ */
+static inline void _spi_master_vec_pinmux_helper(uint32_t pinmux,
+ Sercom *const sercom, uint8_t padnum)
+{
+ struct system_pinmux_config pin_conf;
+
+ if (pinmux == PINMUX_DEFAULT) {
+ pinmux = _sercom_get_default_pad(sercom, padnum);
+ }
+
+ if (pinmux == PINMUX_UNUSED) {
+ return;
+ }
+
+ system_pinmux_get_config_defaults(&pin_conf);
+ pin_conf.mux_position = pinmux & 0xFFFF;
+ system_pinmux_pin_set_config(pinmux >> 16, &pin_conf);
+};
+
+/** \endcond */
+
+/** @} */
+
+/**
+ * \brief Initialize hardware and driver instance
+ *
+ * This function configures the clock system for the specified SERCOM module,
+ * sets up the related pins and their MUX, initializes the SERCOM in SPI master
+ * mode, and prepares the driver instance for operation.
+ *
+ * \pre \ref system_init() must have been called prior to this function.
+ *
+ * The SERCOM SPI module is left disabled after initialization, and must be
+ * enabled with \ref spi_master_vec_enable() before a transfer can be done.
+ *
+ * \param[out] module Driver instance to initialize.
+ * \param[in,out] sercom SERCOM module to initialize and associate driver
+ * instance with.
+ * \param[in] config Driver configuration to use.
+ *
+ * \return Status of initialization.
+ * \retval STATUS_OK if initialization succeeded.
+ * \retval STATUS_ERR_INVALID_ARG if driver has been misconfigured.
+ */
+enum status_code spi_master_vec_init(struct spi_master_vec_module *const module,
+ Sercom *const sercom, const struct spi_master_vec_config *const config)
+{
+ Assert(module);
+ Assert(sercom);
+ Assert(config);
+
+ enum status_code status;
+ SercomSpi *const spi_hw = &(sercom->SPI);
+ struct system_gclk_chan_config gclk_chan_conf;
+ uint16_t tmp_baud;
+ uint32_t sercom_index = _sercom_get_sercom_inst_index((Sercom *)spi_hw);
+#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
+ uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+#else
+ uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+#endif
+ uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ uint32_t gclk_hz;
+
+ module->sercom = sercom;
+
+ /* Enable clock for the module interface */
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+
+ /* Set up the GCLK for the module */
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->gclk_generator;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->gclk_generator, false);
+
+ _spi_master_vec_wait_for_sync(spi_hw);
+
+ /* Set up the SERCOM SPI module as master */
+ spi_hw->CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3);
+ spi_hw->CTRLA.reg |= (uint32_t)config->mux_setting
+ | config->transfer_mode
+ | config->data_order
+ | ((config->run_in_standby || system_is_debugger_present()) ?
+ SERCOM_SPI_CTRLA_RUNSTDBY : 0);
+
+ /* Get baud value from configured baudrate and internal clock rate */
+ gclk_hz = system_gclk_chan_get_hz(gclk_index);
+ status = _sercom_get_sync_baud_val(config->baudrate, gclk_hz, &tmp_baud);
+
+ if (status != STATUS_OK) {
+ /* Baud rate calculation error! */
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ spi_hw->BAUD.reg = (uint8_t)tmp_baud;
+
+ /* Configure the pin multiplexers */
+ _spi_master_vec_pinmux_helper(config->pinmux_pad0, sercom, 0);
+ _spi_master_vec_pinmux_helper(config->pinmux_pad3, sercom, 3);
+
+ /* SERCOM PAD1 and PAD2 are used for slave SS.
+ * This is a SPI master driver, so control of slave SS must be left to
+ * the PORT module, i.e., peripheral MUX should not be set for that pin.
+ * DOPO controls which PAD is used for slave SS:
+ * If DOPO is odd, SERCOM_PAD1 is SS: SERCOM_PAD2 can be MUXed.
+ * If DOPO is even, SERCOM_PAD2 is SS: SERCOM_PAD1 can be MUXed.
+ */
+ if (config->mux_setting & (1 << SERCOM_SPI_CTRLA_DOPO_Pos)) {
+ _spi_master_vec_pinmux_helper(config->pinmux_pad2, sercom, 2);
+ } else {
+ _spi_master_vec_pinmux_helper(config->pinmux_pad1, sercom, 1);
+ }
+
+ /* Initialize our instance and register interrupt handler + data */
+ module->rx_bufdesc_ptr = NULL;
+ module->tx_bufdesc_ptr = NULL;
+ module->direction = SPI_MASTER_VEC_DIRECTION_IDLE;
+ module->status = STATUS_OK;
+#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE(module->busy_semaphore);
+#endif
+
+ _sercom_set_handler(sercom_index, _spi_master_vec_int_handler);
+ _sercom_instances[sercom_index] = module;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Enable the SERCOM SPI module
+ *
+ * This function must be called after \ref spi_master_vec_init() before a
+ * transfer can be started.
+ *
+ * \param[in,out] module Driver instance to operate on.
+ */
+void spi_master_vec_enable(const struct spi_master_vec_module *const module)
+{
+ Assert(module);
+ Assert(module->sercom);
+
+ SercomSpi *const spi_hw = &(module->sercom->SPI);
+
+ spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE | SERCOM_SPI_INTFLAG_RXC
+ | SERCOM_SPI_INTFLAG_TXC;
+
+ _spi_master_vec_wait_for_sync(spi_hw);
+
+ spi_hw->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE;
+
+ system_interrupt_enable(_sercom_get_interrupt_vector(module->sercom));
+}
+
+/**
+ * \brief Disable the SERCOM SPI module
+ *
+ * \param[in,out] module Driver instance to operate on.
+ */
+void spi_master_vec_disable(struct spi_master_vec_module *const module)
+{
+ Assert(module);
+ Assert(module->sercom);
+
+ SercomSpi *const spi_hw = &(module->sercom->SPI);
+
+ system_interrupt_disable(_sercom_get_interrupt_vector(module->sercom));
+
+ _spi_master_vec_wait_for_sync(spi_hw);
+
+ spi_hw->INTENCLR.reg = SERCOM_SPI_INTENCLR_MASK;
+ spi_hw->INTFLAG.reg = SERCOM_SPI_INTFLAG_MASK;
+ spi_hw->CTRLB.reg = 0;
+ spi_hw->CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE;
+ module->rx_bufdesc_ptr = NULL;
+ module->tx_bufdesc_ptr = NULL;
+ module->direction = SPI_MASTER_VEC_DIRECTION_IDLE;
+ module->status = STATUS_OK;
+}
+
+/**
+ * \brief Reset the SERCOM SPI module
+ *
+ * This function will disable and reset the SPI module to its power on default
+ * values.
+ *
+ * \param[in,out] module Pointer to a driver instance.
+ */
+void spi_master_vec_reset(struct spi_master_vec_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->sercom);
+
+ SercomSpi *const spi_hw = &(module->sercom->SPI);
+
+ /* Disable the module */
+ spi_master_vec_disable(module);
+
+ _spi_master_vec_wait_for_sync(spi_hw);
+
+ /* Software reset the module */
+ spi_hw->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST;
+
+#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE(module->busy_semaphore);
+#endif
+}
+
+/**
+ * \brief Start vectored I/O transfer
+ *
+ * This function initiates a uni- or bidirectional SPI transfer from/to any
+ * number of data buffers. The transfer is interrupt-driven and will run in the
+ * background, after this function has returned.
+ *
+ * The buffers to transmit from or receive into must be described in arrays of
+ * buffer descriptors. These arrays \e must end with descriptors that specify
+ * zero buffer length. The first descriptor in an array can \e not specify zero
+ * length. The number of bytes to transmit and to receive do not have to be
+ * equal.
+ *
+ * If the address for a receive buffer is set to \c NULL, the received bytes
+ * corresponding to that buffer descriptor will be discarded. This is useful if
+ * slave is already set up to transfer a number of bytes, but the master has no
+ * available buffer to receive them into. As an example, to receive the two
+ * first bytes and discard the 128 following, the buffer descriptors could be:
+\code
+ struct spi_master_vec_bufdesc rx_buffers[3] = {
+ // Read two status bytes
+ {.data = status_buffer, .length = 2},
+ // Discard 128 data bytes
+ {.data = NULL, .length = 128},
+ // End of reception
+ {.length = 0},
+ };
+\endcode
+ *
+ * To initiate a unidirectional transfer, pass \c NULL as the address of either
+ * buffer descriptor array, like this:
+\code
+ // Transmit some buffers
+ spi_master_vec_transceive_buffer_job(&module, tx_buffers, NULL);
+
+ // Receive some buffers
+ spi_master_vec_transceive_buffer_job(&module, NULL, rx_buffers);
+\endcode
+ *
+ * \pre \ref spi_master_vec_init() and \ref spi_master_vec_enable() must have
+ * been called before this function.
+ *
+ * \param[in,out] module Driver instance to operate on.
+ * \param[in] tx_bufdescs address of buffer descriptor array for bytes to
+ * transmit.
+ * \arg \c NULL if the transfer is a simplex read.
+ * \param[in,out] rx_bufdescs address of buffer descriptor array for storing
+ * received bytes.
+ * \arg \c NULL if the transfer is a simplex write.
+ *
+ * \return Status of transfer start.
+ * \retval STATUS_OK if transfer was started.
+ * \retval STATUS_BUSY if a transfer is already on-going.
+ */
+enum status_code spi_master_vec_transceive_buffer_job(
+ struct spi_master_vec_module *const module,
+ struct spi_master_vec_bufdesc tx_bufdescs[],
+ struct spi_master_vec_bufdesc rx_bufdescs[])
+{
+ Assert(module);
+ Assert(module->sercom);
+ Assert(tx_bufdescs || rx_bufdescs);
+
+ SercomSpi *const spi_hw = &(module->sercom->SPI);
+ uint32_t tmp_ctrlb;
+ uint8_t tmp_intenset;
+
+ system_interrupt_enter_critical_section();
+ if (module->status == STATUS_BUSY) {
+ system_interrupt_leave_critical_section();
+ return STATUS_BUSY;
+ } else {
+ module->status = STATUS_BUSY;
+ system_interrupt_leave_critical_section();
+ }
+
+#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE(module->busy_semaphore);
+#endif
+
+ module->tx_bufdesc_ptr = tx_bufdescs;
+ module->rx_bufdesc_ptr = rx_bufdescs;
+
+ if (tx_bufdescs && rx_bufdescs) {
+ Assert(tx_bufdescs[0].length);
+ Assert(rx_bufdescs[0].length);
+
+ module->direction = SPI_MASTER_VEC_DIRECTION_BOTH;
+ module->tx_length = tx_bufdescs[0].length;
+ module->tx_head_ptr = tx_bufdescs[0].data;
+ module->rx_length = rx_bufdescs[0].length;
+ module->rx_head_ptr = rx_bufdescs[0].data;
+ module->tx_lead_on_rx = 0;
+ tmp_ctrlb = SERCOM_SPI_CTRLB_RXEN;
+ tmp_intenset = SERCOM_SPI_INTFLAG_DRE | SERCOM_SPI_INTFLAG_RXC;
+ } else {
+ if (tx_bufdescs) {
+ Assert(tx_bufdescs[0].length);
+
+ module->direction = SPI_MASTER_VEC_DIRECTION_WRITE;
+ module->tx_length = tx_bufdescs[0].length;
+ module->tx_head_ptr = tx_bufdescs[0].data;
+ tmp_ctrlb = 0;
+ tmp_intenset = SERCOM_SPI_INTFLAG_DRE;
+ } else {
+ Assert(rx_bufdescs[0].length);
+
+ module->direction = SPI_MASTER_VEC_DIRECTION_READ;
+ module->rx_length = rx_bufdescs[0].length;
+ module->rx_head_ptr = rx_bufdescs[0].data;
+ module->tx_lead_on_rx = 0;
+ tmp_ctrlb = SERCOM_SPI_CTRLB_RXEN;
+ tmp_intenset = SERCOM_SPI_INTFLAG_DRE | SERCOM_SPI_INTFLAG_RXC;
+ }
+ }
+
+ /* Ensure the SERCOM is sync'ed before writing these registers */
+ _spi_master_vec_wait_for_sync(spi_hw);
+
+ spi_hw->CTRLB.reg = tmp_ctrlb;
+ spi_hw->INTENSET.reg = tmp_intenset;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Interrupt handler
+ *
+ * \param[in] sercom_index SERCOM instance number passed from the master SERCOM
+ * driver.
+ */
+static void _spi_master_vec_int_handler(uint8_t sercom_index)
+{
+ struct spi_master_vec_module *const module =
+ _sercom_instances[sercom_index];
+ enum _spi_master_vec_direction dir = module->direction;
+ SercomSpi *const spi_hw = &(module->sercom->SPI);
+ uint8_t int_status;
+
+ int_status = spi_hw->INTFLAG.reg ;
+ int_status &= spi_hw->INTENSET.reg;
+
+ if (int_status & SERCOM_SPI_INTFLAG_DRE) {
+ uint_fast8_t tx_lead_on_rx = module->tx_lead_on_rx;
+
+ /* If TX is ahead of RX by 2+ bytes, allow RX to catch up.
+ * Note: will only happen _once_ per READ or BOTH.
+ */
+ if ((tx_lead_on_rx >= 2) && (dir != SPI_MASTER_VEC_DIRECTION_WRITE)) {
+ Assert((dir == SPI_MASTER_VEC_DIRECTION_READ)
+ || (dir == SPI_MASTER_VEC_DIRECTION_BOTH));
+ Assert(int_status & SERCOM_SPI_INTFLAG_RXC);
+ /* Otherwise, we can send more bytes */
+ } else {
+ module->tx_lead_on_rx = ++tx_lead_on_rx;
+
+ /* If doing a READ, just send 0 to trigger the transfer */
+ if (dir == SPI_MASTER_VEC_DIRECTION_READ) {
+ uint32_t tx_lead_limit;
+
+ spi_hw->DATA.reg = 0;
+
+check_for_read_end:
+ /* With current TX'ed bytes, will we get the last RX byte?
+ * If so, we can disable the DRE interrupt to stop transmitting.
+ *
+ * Since a buffer can have minimum 1 byte length, this check is
+ * simplified by first checking if the RX end is so close that
+ * the max. 2 byte lead of TX may actually fill the buffers.
+ */
+ tx_lead_limit = (module->rx_bufdesc_ptr + 1)->length;
+
+ if (!tx_lead_limit || !(module->rx_bufdesc_ptr + 2)->length) {
+ tx_lead_limit += module->rx_length;
+
+ if (tx_lead_on_rx >= tx_lead_limit) {
+ spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE;
+ }
+ }
+ /* For WRITE and BOTH, output current byte */
+ } else {
+ spi_master_vec_buflen_t tx_length;
+ uint8_t *tx_head_ptr;
+
+ tx_head_ptr = module->tx_head_ptr;
+ spi_hw->DATA.reg = *(tx_head_ptr++);
+
+ /* Check if this was the last byte to send */
+ tx_length = module->tx_length - 1;
+
+ if (tx_length) {
+ module->tx_head_ptr = tx_head_ptr;
+ module->tx_length = tx_length;
+ } else {
+ /* Any more buffers left to send, perhaps? */
+ tx_length = (++module->tx_bufdesc_ptr)->length;
+
+ if (tx_length) {
+ module->tx_head_ptr = module->tx_bufdesc_ptr->data;
+ module->tx_length = tx_length;
+ } else {
+ if (dir == SPI_MASTER_VEC_DIRECTION_WRITE) {
+ /* Disable DRE and enable TXC to end WRITE */
+ spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE;
+ spi_hw->INTENSET.reg = SERCOM_SPI_INTFLAG_TXC;
+ } else {
+ /* For BOTH, check if we still have bytes to read */
+ dir = SPI_MASTER_VEC_DIRECTION_READ;
+ module->direction = dir;
+ goto check_for_read_end;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* For READ and BOTH, store the received byte */
+ if (int_status & SERCOM_SPI_INTFLAG_RXC) {
+ spi_master_vec_buflen_t rx_length;
+ uint8_t *rx_head_ptr;
+
+ rx_head_ptr = module->rx_head_ptr;
+ if (rx_head_ptr != NULL) {
+ *(rx_head_ptr++) = spi_hw->DATA.reg;
+ } else {
+ uint8_t dummy;
+ dummy = spi_hw->DATA.reg;
+ UNUSED(dummy);
+ }
+ module->tx_lead_on_rx--;
+
+ /* Check if this was the last byte to receive */
+ rx_length = module->rx_length - 1;
+
+ if (rx_length) {
+ module->rx_head_ptr = rx_head_ptr;
+ module->rx_length = rx_length;
+ } else {
+ /* Any more buffers left to receive into? */
+ rx_length = (++module->rx_bufdesc_ptr)->length;
+
+ if (rx_length) {
+ module->rx_head_ptr = module->rx_bufdesc_ptr->data;
+ module->rx_length = rx_length;
+ } else {
+ /* Disable the SPI receiver (instant effect) and RX interrupt */
+ spi_hw->CTRLB.reg = 0;
+ spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_RXC;
+
+ if (dir == SPI_MASTER_VEC_DIRECTION_READ) {
+ /* If doing READ, end the transaction here */
+ dir = SPI_MASTER_VEC_DIRECTION_IDLE;
+ module->direction = dir;
+ module->status = STATUS_OK;
+#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR(module->busy_semaphore);
+#endif
+ } else {
+ /* If doing BOTH, change direction to WRITE */
+ dir = SPI_MASTER_VEC_DIRECTION_WRITE;
+ module->direction = dir;
+ }
+ }
+ }
+ }
+
+ /* For WRITE */
+ if (int_status & SERCOM_SPI_INTFLAG_TXC) {
+ /* End transaction here, since last byte has been sent */
+ spi_hw->INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC;
+
+ dir = SPI_MASTER_VEC_DIRECTION_IDLE;
+ module->direction = dir;
+ module->status = STATUS_OK;
+#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR(module->busy_semaphore);
+#endif
+ }
+}
+
+/**
+ * @}
+ */ \ No newline at end of file
diff --git a/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h
new file mode 100644
index 000000000..a10ae22f1
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/spi_master_vec/spi_master_vec.h
@@ -0,0 +1,692 @@
+/**
+ * \file
+ *
+ * \brief SERCOM SPI master with vectored I/O driver include
+ *
+ * Copyright (C) 2013-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#ifndef SPI_MASTER_VEC_H
+#define SPI_MASTER_VEC_H
+
+#include <compiler.h>
+#include <gclk.h>
+#include <port.h>
+#include <spi.h>
+#include <status_codes.h>
+#include <conf_spi_master_vec.h>
+
+/**
+ * \defgroup asfdoc_sam0_sercom_spi_master_vec_group SAM Serial Peripheral Interface Master Driver w/ Vectored I/O (SERCOM SPI)
+ *
+ * This driver for Atmel&reg; | SMART SAM devices provides an interface for the configuration
+ * and operation of the SERCOM module in SPI master mode and uses vectored I/O
+ * for data transfers.
+ *
+ * The following peripherals are used by this driver:
+ * - SERCOM (Serial Communication Interface)
+ *
+ * The following devices can use this driver:
+ * - Atmel | SMART SAM D20/D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D09/D10/D11
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM DA1
+ * - Atmel | SMART SAM C20/C21
+ *
+ * The reader is assumed to be familiar with the regular SERCOM SPI driver, and
+ * how it is configured and operated. Configuration of this driver is done a
+ * similar way and actually re-uses several enumerations (configuration values)
+ * from the regular SERCOM SPI driver.
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_prerequisites
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_module_overview
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_special_considerations
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_info
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_examples
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_api_overview
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_prerequisites Prerequisites
+ *
+ * This driver uses the \ref asfdoc_sam0_system_clock_group "SYSTEM clock driver"
+ * to select the SERCOM's clock source and to configure the SERCOM for the
+ * desired baud rate. Ensure that the selected clock source is configured and
+ * that the clock system is initialized. This is typically done indirectly with
+ * \ref system_init(), or directly with \ref system_clock_init().
+ *
+ * According to the datasheet, the minimum and maximum limits for the baud rate
+ * is given by: \f$ \frac{1}{2^{17}} \times f_{clk} \le f_{baud}
+ * \le \frac{1}{2} \times f_{clk} \f$.
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_module_overview Module Overview
+ *
+ * This SERCOM SPI master driver supports uni- and bidirectional transfers of
+ * 8-bit data with vectored I/O, also know as scatter/gather.
+ * It does not implement control of SS or slave addressing since the intended
+ * usage is in stacks which usually have their own protocols and handshaking
+ * schemes.
+ *
+ *
+ * \subsection asfdoc_sam0_sercom_spi_master_vectored_io Vectored I/O
+ *
+ * Vectored I/O enables the transfer of data from/to any number of buffers with
+ * arbitrary memory locations without having to do several transfers, i.e., one
+ * buffer at a time. This feature is useful in stacks because it allows each
+ * layer of the stack to have a dedicated data buffer, thus avoiding the need
+ * for a centralized data buffer that the different layers must use in
+ * cooperation.
+ *
+ * The vectored I/O relies on arrays of buffer descriptors which must be passed
+ * to the driver to start a transfer. These buffer descriptors specify where in
+ * memory each buffer is, and how large they are.
+ * \ref asfdoc_sam0_vectored_io_example "The figure below" illustrates this
+ * for an example with three buffers of varying sizes that are transmitted.
+ *
+ * \anchor asfdoc_sam0_vectored_io_example
+ * \dot
+digraph bufptr_to_spiord {
+ rankdir=LR;
+ subgraph cluster_bufptr {
+ style=invis;
+ bufptr_label [shape=none, label="Buffer descriptors"];
+ bufptrs [shape=record, label="<bf1> [0]|<bf2> [1]|<bf3> [2]|<bf4> [3]"];
+ }
+ subgraph cluster_buf {
+ style=invis;
+ buf_label [shape=none, label="Memory layout"];
+ bufs [shape=record, label="...|<b1>&quot;yy&quot;|...|<b3>&quot;z&quot;|<b2>&quot;xxx&quot;|..."];
+ }
+ subgraph cluster_spiord {
+ style=invis;
+ spiord_label [shape=none, label="SPI transmission"];
+ spiord [shape=record, label="<s1>&quot;yy&quot;|<s2>&quot;xxx&quot;|<s3>&quot;z&quot;"];
+ }
+ bufptrs:bf1 -> bufs:b1 -> spiord:s1;
+ bufptrs:bf2 -> bufs:b2 -> spiord:s2;
+ bufptrs:bf3 -> bufs:b3 -> spiord:s3;
+ bufptrs:bf4 -> "none";
+}
+ * \enddot
+ *
+ * Note that the last descriptor \e must indicate no next buffer in order for
+ * the driver to detect that the end of the buffer list has been reached. This
+ * means that for \c N buffers, \c N+1 buffer descriptors are needed.
+ *
+ * Bidirectional transfers are supported without any restrictions on the buffer
+ * descriptors, so the number of bytes and buffers to receive and transmit do
+ * \e not have to be the same.
+ *
+ * \sa spi_master_vec_transceive_buffer_job() for details on starting transfers.
+ *
+ *
+ * \subsection asfdoc_sam0_sercom_spi_master_os_support OS support
+ *
+ * Since this driver is interrupt-driven, it is possible for the MCU to run
+ * other code while a transfer is on-going.
+ *
+ * In a single-threaded application, this can be achieved by starting a transfer
+ * and then avoid any waiting for completion until absolutely required, e.g.,
+ * when a new transfer is needed.
+ *
+ * But in a multi-threaded application, for example based on FreeRTOS, one can
+ * utilize \e semaphores to let the OS know when a function is waiting and thus
+ * blocking the thread, and that other threads can be run instead. Put another
+ * way, the waiting can be made efficient.
+ *
+ * This driver has an internal semaphore which is used to signal to the OS
+ * whenever a function is waiting for a transfer to complete. And since the
+ * semaphore datatypes and functions are OS-specific, the support has been made
+ * configurable by the use of macros. Note that support for FreeRTOS is already
+ * implemented, but must be enabled.
+ *
+ * \sa CONF_SPI_MASTER_VEC_OS_SUPPORT for more on the configurable OS support.
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_special_considerations Special Considerations
+ *
+ * \subsection asfdoc_sam0_sercom_spi_master_vec_special_isr Interrupt safety
+ *
+ * This driver should not be used within interrupt contexts. The reason for this
+ * is that the driver itself is interrupt driven. Further, the configurable OS
+ * support is implemented with the assumption that transfers are only started
+ * in threads, not in interrupt service routines, because it gives the simplest
+ * API.
+ *
+ *
+ * \subsection asfdoc_sam0_sercom_spi_master_vec_special_mux Signal MUX
+ *
+ * The SERCOM module has two layers of signal multiplexing in SPI mode:
+ * -# SERCOM pad MUX: This routes the SPI signals to internal lines.
+ * -# PORT pin MUX: This routes the internal line to a device pin.
+ *
+ * Both of these layers are configured in the \ref spi_master_vec_config
+ * "configuration structure", using the members named \c mux_setting and
+ * \c pinmux_padN. These must be set in combination.
+ *
+ * The driver supplies values for the
+ * \ref spi_master_vec_config::mux_setting "SERCOM pad MUX" from the standard
+ * ASF SERCOM SPI driver. For the PORT pin MUX configuration, refer to the
+ * peripheral include file for the device (\c pio_samd20XNN.h ) and use the
+ * macros that are prefixed with \c PINMUX_, such as
+ * \c PINMUX_PA04D_SERCOM0_PAD0. It is also possible to use the default pin MUX
+ * setting for a SERCOM pad by using the \ref PINMUX_DEFAULT macro. The defaults
+ * are defined in the file \ref sercom_pinout.h.
+ *
+ * Note that for \ref spi_master_vec_init() to function properly with the macro
+ * \ref PINMUX_DEFAULT, the order of the values in \c pinmux_padN \e must be
+ * correct, i.e., \c pinmux_pad0 must contain the pin MUX setting for
+ * multiplexing SERCOM pad 0, and so on.
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_extra_info Extra Information
+ *
+ * For extra information, see
+ * \subpage asfdoc_sam0_sercom_spi_master_vec_extra. This includes:
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_acronyms
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_dependencies
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_errata
+ * - \ref asfdoc_sam0_sercom_spi_master_vec_extra_history
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_sercom_spi_master_vec_exqsg.
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_api_overview API Overview
+ *
+ * @{
+ */
+
+/**
+ * Driver configuration structure
+ *
+ * \sa asfdoc_sam0_sercom_spi_master_vec_special_considerations for more
+ * information regarding SERCOM pad and pin MUX.
+ */
+struct spi_master_vec_config {
+ /** Baud rate in Hertz. */
+ uint32_t baudrate;
+ /** GCLK generator to use for the SERCOM. */
+ enum gclk_generator gclk_generator;
+ /** Enabled in sleep modes. */
+ bool run_in_standby;
+ /** SERCOM pad MUX setting. */
+ enum spi_signal_mux_setting mux_setting;
+ /** Transfer mode. */
+ enum spi_transfer_mode transfer_mode;
+ /** Data order. */
+ enum spi_data_order data_order;
+ /** Pin MUX setting for SERCOM pad 0. */
+ uint32_t pinmux_pad0;
+ /** Pin MUX setting for SERCOM pad 1. */
+ uint32_t pinmux_pad1;
+ /** Pin MUX setting for SERCOM pad 2. */
+ uint32_t pinmux_pad2;
+ /** Pin MUX setting for SERCOM pad 4. */
+ uint32_t pinmux_pad3;
+};
+
+/** Buffer length container. */
+typedef uint16_t spi_master_vec_buflen_t;
+
+/** Buffer descriptor structure. */
+struct spi_master_vec_bufdesc {
+ /** Pointer to buffer start. */
+ void *data;
+ /** Length of buffer. */
+ spi_master_vec_buflen_t length;
+};
+
+/** Transfer direction */
+enum _spi_master_vec_direction {
+ SPI_MASTER_VEC_DIRECTION_READ,
+ SPI_MASTER_VEC_DIRECTION_WRITE,
+ SPI_MASTER_VEC_DIRECTION_BOTH,
+ SPI_MASTER_VEC_DIRECTION_IDLE,
+};
+
+/** Driver instance. */
+struct spi_master_vec_module {
+#if !defined(__DOXYGEN__)
+ Sercom *volatile sercom;
+ volatile bool locked;
+ volatile enum _spi_master_vec_direction direction;
+ volatile enum status_code status;
+ volatile spi_master_vec_buflen_t rx_length;
+ volatile spi_master_vec_buflen_t tx_length;
+ uint8_t *volatile rx_head_ptr;
+ uint8_t *volatile tx_head_ptr;
+ volatile uint_fast8_t tx_lead_on_rx;
+ struct spi_master_vec_bufdesc *volatile rx_bufdesc_ptr;
+ struct spi_master_vec_bufdesc *volatile tx_bufdesc_ptr;
+# ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE busy_semaphore;
+# endif
+#endif
+};
+
+/**
+ * \name Configuration and Initialization
+ * @{
+ */
+
+/**
+ * \brief Initialize configuration with default values.
+ *
+ * \param[out] config Configuration struct to initialize.
+ */
+static inline void spi_master_vec_get_config_defaults(
+ struct spi_master_vec_config *const config)
+{
+ config->baudrate = 100000;
+ config->gclk_generator = GCLK_GENERATOR_0;
+ config->run_in_standby = false;
+ config->mux_setting = SPI_SIGNAL_MUX_SETTING_D;
+ config->transfer_mode = SPI_TRANSFER_MODE_0;
+ config->data_order = SPI_DATA_ORDER_MSB;
+ config->pinmux_pad0 = PINMUX_DEFAULT;
+ config->pinmux_pad1 = PINMUX_DEFAULT;
+ config->pinmux_pad2 = PINMUX_DEFAULT;
+ config->pinmux_pad3 = PINMUX_DEFAULT;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum status_code spi_master_vec_init(struct spi_master_vec_module *const module,
+ Sercom *const sercom, const struct spi_master_vec_config *const config);
+
+/** @} */
+
+/**
+ * \name Enable/Disable and Reset
+ * @{
+ */
+
+void spi_master_vec_enable(const struct spi_master_vec_module *const module);
+void spi_master_vec_disable(struct spi_master_vec_module *const module);
+void spi_master_vec_reset(struct spi_master_vec_module *const module);
+
+/** @} */
+
+/**
+ * \name Lock/Unlock
+ * @{
+ */
+
+/**
+ * \brief Attempt to get lock on driver instance
+ *
+ * This function checks the instance's lock, which indicates whether or not it
+ * is currently in use, and sets the lock if it was not already set.
+ *
+ * The purpose of this is to enable exclusive access to driver instances, so
+ * that, e.g., transactions by different services will not interfere with each
+ * other.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock.
+ *
+ * \retval STATUS_OK if the module was locked.
+ * \retval STATUS_BUSY if the module was already locked.
+ */
+static inline enum status_code spi_master_vec_lock(
+ struct spi_master_vec_module *const module)
+{
+ enum status_code status;
+
+ system_interrupt_enter_critical_section();
+
+ if (module->locked) {
+ status = STATUS_BUSY;
+ } else {
+ module->locked = true;
+ status = STATUS_OK;
+ }
+
+ system_interrupt_leave_critical_section();
+
+ return status;
+}
+
+/**
+ * \brief Unlock driver instance
+ *
+ * This function clears the instance lock, indicating that it is available for
+ * use.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock.
+ */
+static inline void spi_master_vec_unlock(
+ struct spi_master_vec_module *const module)
+{
+ module->locked = false;
+}
+
+/** @} */
+
+/**
+ * \name Read/Write and Status
+ * @{
+ */
+
+enum status_code spi_master_vec_transceive_buffer_job(
+ struct spi_master_vec_module *const module,
+ struct spi_master_vec_bufdesc tx_bufdescs[],
+ struct spi_master_vec_bufdesc rx_bufdescs[]);
+
+/**
+ * \brief Get current status of transfer.
+ *
+ * \param[in] module Driver instance to operate on.
+ *
+ * \return Current status of driver instance.
+ * \retval STATUS_OK if idle and previous transfer succeeded.
+ * \retval STATUS_BUSY if a transfer is ongoing.
+ * \retval <other> if previous transfer failed.
+ */
+static inline enum status_code spi_master_vec_get_job_status(
+ const struct spi_master_vec_module *const module)
+{
+ return module->status;
+}
+
+/**
+ * \brief Get status of transfer upon job end.
+ *
+ * \param[in] module Driver instance to operate on.
+ *
+ * \return Current status of driver instance.
+ * \retval STATUS_OK if idle and previous transfer succeeded.
+ * \retval <other> if previous transfer failed.
+ */
+static inline enum status_code spi_master_vec_get_job_status_wait(
+ const struct spi_master_vec_module *const module)
+{
+ enum status_code status;
+
+#ifdef CONF_SPI_MASTER_VEC_OS_SUPPORT
+ CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE(module->busy_semaphore);
+ status = spi_master_vec_get_job_status(module);
+ CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE(module->busy_semaphore);
+#else
+ do {
+ status = spi_master_vec_get_job_status(module);
+ } while (status == STATUS_BUSY);
+#endif
+
+ return status;
+}
+
+
+/**
+ * \brief Start vectored I/O transfer, wait for it to end.
+ *
+ * \param[in,out] module Driver instance to operate on.
+ * \param[in] tx_bufdescs address of buffer descriptor array for bytes to
+ * transmit.
+ * \arg \c NULL if the transfer is a simplex read.
+ * \param[in,out] rx_bufdescs address of buffer descriptor array for storing
+ * received bytes.
+ * \arg \c NULL if the transfer is a simplex write.
+ *
+ * \return Status of transfer start.
+ * \retval STATUS_OK if transfer succeeded.
+ * \retval STATUS_BUSY if a transfer was already on-going.
+ * \retval <other> if transfer failed.
+ */
+static inline enum status_code spi_master_vec_transceive_buffer_wait(
+ struct spi_master_vec_module *const module,
+ struct spi_master_vec_bufdesc tx_bufdescs[],
+ struct spi_master_vec_bufdesc rx_bufdescs[])
+{
+ enum status_code status;
+
+ status = spi_master_vec_transceive_buffer_job(module, tx_bufdescs,
+ rx_bufdescs);
+
+ if (status == STATUS_BUSY) {
+ return status;
+ }
+
+ return spi_master_vec_get_job_status_wait(module);
+}
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * \name OS Support Configuration
+ * @{
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_OS_SUPPORT
+ * \brief Enable support for OS
+ *
+ * Defining this symbol will enable support for an OS, e.g., FreeRTOS, by using
+ * the macros in this group:
+ * - \ref CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE
+ * - \ref CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE
+ * - \ref CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE
+ * - \ref CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE
+ * - \ref CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE
+ * - \ref CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR
+ *
+ * The user must ensure that these macros map to the implementation for the OS
+ * that is used. Further, required includes must be added alongside these macros
+ * in \ref conf_spi_master_vec.h.
+ *
+ * The purpose of this configuration is to enable usage of the OS' semaphore
+ * system to wait for transfers to end rather than continuously polling the
+ * transfer status, which is an inefficient approach.
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_SEMAPHORE_TYPE
+ * \brief Semaphore datatype
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_CREATE_SEMAPHORE
+ * \brief Create/initialize semaphore
+ *
+ * \param semaphore Semaphore member in driver instance.
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_DELETE_SEMAPHORE
+ * \brief Delete semaphore
+ *
+ * \param semaphore Semaphore member in driver instance.
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_TAKE_SEMAPHORE
+ * \brief Wait for and take semaphore
+ *
+ * \param semaphore Semaphore member in driver instance.
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE
+ * \brief Give semaphore back
+ *
+ * \param semaphore Semaphore member in driver instance.
+ */
+
+/**
+ * \def CONF_SPI_MASTER_VEC_GIVE_SEMAPHORE_FROM_ISR
+ * \brief Give semaphore back from an ISR
+ *
+ * \param semaphore Semaphore member in driver instance.
+ */
+
+/** @} */
+
+/**
+ * @}
+ */
+
+/**
+ * \page asfdoc_sam0_sercom_spi_master_vec_extra Extra Information for SERCOM SPI Master Driver w/ Vectored I/O
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_extra_acronyms Acronyms
+ *
+ * The table below presents the acronyms used in this module.
+ *
+ * <table>
+ * <tr>
+ * <th>Acronym</td>
+ * <th>Description</td>
+ * </tr>
+ * <tr>
+ * <td>GCLK</td>
+ * <td>Generic Clock</td>
+ * </tr>
+ * <tr>
+ * <td>MISO</td>
+ * <td>Master Input, Slave Output</td>
+ * </tr>
+ * <tr>
+ * <td>MOSI</td>
+ * <td>Master Output, Slave Input</td>
+ * </tr>
+ * <tr>
+ * <td>SCK</td>
+ * <td>Serial Clock</td>
+ * </tr>
+ * <tr>
+ * <td>SPI</td>
+ * <td>Serial Peripheral Interface</td>
+ * </tr>
+ * <tr>
+ * <td>SS</td>
+ * <td>Slave Select</td>
+ * </tr>
+ * </table>
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_extra_dependencies Dependencies
+ *
+ * This driver has the following dependencies:
+ * - \ref asfdoc_sam0_system_group "System driver"
+ * - \ref group_sam0_utils "Compiler driver"
+ * - \ref asfdoc_sam0_port_group "Port driver"
+ * - \ref Common SERCOM driver base
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_extra_errata Errata
+ *
+ * There are no errata related to this driver.
+ *
+ *
+ * \section asfdoc_sam0_sercom_spi_master_vec_extra_history Module History
+ *
+ * An overview of the module history is presented in the table below, with
+ * details on the enhancements and fixes made to the module since its first
+ * release. The current version of this corresponds to the newest version in the
+ * table.
+ *
+ * <table>
+ * <tr>
+ * <th>Changelog</th>
+ * </tr>
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * </table>
+ */
+
+/**
+ * \page asfdoc_sam0_sercom_spi_master_vec_exqsg Examples for SERCOM SPI Master Driver w/ Vectored I/O
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_sercom_spi_master_vec_group. QSGs are
+ * simple examples with step-by-step instructions to configure and use this
+ * driver in a selection of use cases. Note that QSGs can be compiled as a
+ * standalone application or be added to the user application.
+ *
+ * - \subpage asfdoc_sam0_sercom_spi_master_vec_basic
+ */
+
+ /**
+ * \page asfdoc_sam0_sercom_spi_master_vec_document_revision_history Document Revision History
+ *
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</td>
+ * <th>Date</td>
+ * <th>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>D</td>
+ * <td>12/2014</td>
+ * <td>Add SAM L21/C21 support.</td>
+ * </tr>
+ * <tr>
+ * <td>C</td>
+ * <td>04/2014</td>
+ * <td>Add SAM D10/D11 support.</td>
+ * </tr>
+ * <tr>
+ * <td>B</td>
+ * <td>03/2014</td>
+ * <td>Add SAMR21 support.</td>
+ * </tr>
+ * <tr>
+ * <td>A</td>
+ * <td>01/2014</td>
+ * <td>Initial release</td>
+ * </tr>
+ * </table>
+ */
+
+#endif /* SPI_MASTER_VEC_H */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/usart/docimg/usart_frame.svg b/atmel-samd/asf/sam0/drivers/sercom/usart/docimg/usart_frame.svg
new file mode 100644
index 000000000..2a7550184
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/usart/docimg/usart_frame.svg
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<!-- Generated by Microsoft Visio 11.0, SVG Export, v1.0 usart_frame.svg Page-1 -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:v="http://schemas.microsoft.com/visio/2003/SVGExtensions/" width="6.50273in"
+ height="0.879475in" viewBox="0 0 468.197 63.3222" xml:space="preserve" color-interpolation-filters="sRGB" class="st7">
+ <v:documentProperties v:langID="1044" v:metric="true" v:viewMarkup="false"/>
+
+ <style type="text/css">
+ <![CDATA[
+ .st1 {stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st2 {fill:none;stroke:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72}
+ .st3 {fill:#000000;font-family:Arial;font-size:0.666664em}
+ .st4 {marker-end:url(#mrkr13-134);marker-start:url(#mrkr13-132);stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.24}
+ .st5 {fill:#000000;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:0.08695652173913}
+ .st6 {fill:#ffffff;stroke:none;stroke-linecap:butt;stroke-width:7.2}
+ .st7 {fill:none;fill-rule:evenodd;font-size:12;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
+ ]]>
+ </style>
+
+ <defs id="Markers">
+ <g id="lend13">
+ <path d="M 3 1 L -0 0 L 3 -1 L 3 1 " style="stroke:none"/>
+ </g>
+ <marker id="mrkr13-132" class="st5" v:arrowType="13" v:arrowSize="2" v:setback="33" refX="33" orient="auto"
+ markerUnits="strokeWidth">
+ </marker>
+ <marker id="mrkr13-134" class="st5" v:arrowType="13" v:arrowSize="2" v:setback="34.5" refX="-34.5" orient="auto"
+ markerUnits="strokeWidth">
+ </marker>
+ </defs>
+ <g v:mID="0" v:index="1" v:groupContext="foregroundPage">
+ <v:userDefs>
+ <v:ud v:nameU="ShapeNumCriteria" v:prompt="" v:val="VT4(0,0,0,1,1,&#39;&#39;,0,0,0,1,0,1,)"/>
+ </v:userDefs>
+ <title>Page-1</title>
+ <v:pageProperties v:drawingScale="0.0393701" v:pageScale="0.0393701" v:drawingUnits="24" v:shadowOffsetX="8.50394"
+ v:shadowOffsetY="-8.50394"/>
+ <g id="group3-1" transform="translate(99.4526,-0.72)" v:mID="3" v:groupContext="group">
+ <title>Sheet.3</title>
+ <g id="shape1-2" v:mID="1" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.1</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape2-5" v:mID="2" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.2</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="group4-8" transform="translate(127.799,-0.72)" v:mID="4" v:groupContext="group">
+ <title>Sheet.4</title>
+ <g id="shape5-9" v:mID="5" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.5</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape6-12" v:mID="6" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.6</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="group7-15" transform="translate(156.146,-0.72)" v:mID="7" v:groupContext="group">
+ <title>Sheet.7</title>
+ <g id="shape8-16" v:mID="8" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.8</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape9-19" v:mID="9" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.9</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="group10-22" transform="translate(184.492,-0.72)" v:mID="10" v:groupContext="group">
+ <title>Sheet.10</title>
+ <g id="shape11-23" v:mID="11" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.11</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape12-26" v:mID="12" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.12</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="group13-29" transform="translate(212.838,-0.72)" v:mID="13" v:groupContext="group">
+ <title>Sheet.13</title>
+ <g id="shape14-30" v:mID="14" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.14</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape15-33" v:mID="15" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.15</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="group16-36" transform="translate(241.185,-0.72)" v:mID="16" v:groupContext="group">
+ <title>Sheet.16</title>
+ <g id="shape17-37" v:mID="17" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.17</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape18-40" v:mID="18" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.18</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="group19-43" transform="translate(269.531,-0.72)" v:mID="19" v:groupContext="group">
+ <title>Sheet.19</title>
+ <g id="shape20-44" v:mID="20" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.20</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape21-47" v:mID="21" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.21</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="shape22-50" v:mID="22" v:groupContext="shape" transform="translate(107.957,-0.72)">
+ <title>Sheet.22</title>
+ <desc>1</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="11.95" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>1</text> </g>
+ <g id="shape23-53" v:mID="23" v:groupContext="shape" transform="translate(134.886,-0.72)">
+ <title>Sheet.23</title>
+ <desc>2</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="11.95" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>2</text> </g>
+ <g id="shape24-56" v:mID="24" v:groupContext="shape" transform="translate(163.232,-0.72)">
+ <title>Sheet.24</title>
+ <desc>3</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="11.95" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>3</text> </g>
+ <g id="shape25-59" v:mID="25" v:groupContext="shape" transform="translate(191.579,-0.72)">
+ <title>Sheet.25</title>
+ <desc>4</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="11.95" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>4</text> </g>
+ <g id="shape26-62" v:mID="26" v:groupContext="shape" transform="translate(219.925,-0.72)">
+ <title>Sheet.26</title>
+ <desc>[5]</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="9.73" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>[5]</text> </g>
+ <g id="shape27-65" v:mID="27" v:groupContext="shape" transform="translate(248.271,-0.72)">
+ <title>Sheet.27</title>
+ <desc>[6]</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="9.73" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>[6]</text> </g>
+ <g id="shape28-68" v:mID="28" v:groupContext="shape" transform="translate(275.909,-0.72)">
+ <title>Sheet.28</title>
+ <desc>[7]</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="9.73" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>[7]</text> </g>
+ <g id="shape29-71" v:mID="29" v:groupContext="shape" transform="translate(302.838,-0.72)">
+ <title>Sheet.29</title>
+ <desc>[8]</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="9.73" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>[8]</text> </g>
+ <g id="shape30-74" v:mID="30" v:groupContext="shape" transform="translate(141.916,62.5743) rotate(116.565)">
+ <title>Sheet.30</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="group31-77" transform="translate(297.878,-0.72)" v:mID="31" v:groupContext="group">
+ <title>Sheet.31</title>
+ <g id="shape32-78" v:mID="32" v:groupContext="shape" transform="translate(56.6371,6.6572) rotate(63.4349)">
+ <title>Sheet.32</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape33-81" v:mID="33" v:groupContext="shape" transform="translate(-56.6371,35.0037) rotate(-63.4349)">
+ <title>Sheet.33</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ </g>
+ <g id="shape34-84" v:mID="34" v:groupContext="shape" transform="translate(269.587,34.2837) rotate(-63.4349)">
+ <title>Sheet.34</title>
+ <path d="M0 63.32 L31.69 63.32" class="st1"/>
+ </g>
+ <g id="shape35-87" v:mID="35" v:groupContext="shape" transform="translate(0.24,-0.72)">
+ <title>Sheet.35</title>
+ <path d="M325.98 63.32 L70.87 63.32 L56.69 63.32 L42.52 34.98 L0 34.98" class="st1"/>
+ </g>
+ <g id="shape37-90" v:mID="37" v:groupContext="shape" transform="translate(467.957,97.578) rotate(180)">
+ <title>Sheet.37</title>
+ <path d="M0 63.32 L56.69 63.32" class="st1"/>
+ </g>
+ <g id="shape38-93" v:mID="38" v:groupContext="shape" transform="translate(79.6101,-0.72)">
+ <title>Sheet.38</title>
+ <desc>0</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="11.95" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>0</text> </g>
+ <g id="shape39-96" v:mID="39" v:groupContext="shape" transform="translate(49.8463,-0.72)">
+ <title>Sheet.39</title>
+ <desc>St</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="10.39" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>St</text> </g>
+ <g id="shape40-99" v:mID="40" v:groupContext="shape" transform="translate(8.74394,-0.72)">
+ <title>Sheet.40</title>
+ <desc>(IDLE)</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="18.4252" cy="49.149" width="36.86" height="28.3465"/>
+ <rect x="0" y="34.9757" width="36.8504" height="28.3465" class="st2"/>
+ <text x="6.87" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>(IDLE)</text> </g>
+ <g id="shape41-102" v:mID="41" v:groupContext="shape" transform="translate(361.657,-0.72)">
+ <title>Sheet.41</title>
+ <desc>Sp1</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="7.06" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>Sp1</text> </g>
+ <g id="shape42-105" v:mID="42" v:groupContext="shape" transform="translate(388.586,-0.72)">
+ <title>Sheet.42</title>
+ <desc>[Sp2]</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="4.83" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>[Sp2]</text> </g>
+ <g id="shape43-108" v:mID="43" v:groupContext="shape" transform="translate(422.602,-0.72)">
+ <title>Sheet.43</title>
+ <desc>(St/IDLE)</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="21.2598" cy="49.149" width="42.52" height="28.3465"/>
+ <rect x="0" y="34.9757" width="42.5197" height="28.3465" class="st2"/>
+ <text x="4.81" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>(St/IDLE)</text> </g>
+ <g id="shape44-111" v:mID="44" v:groupContext="shape" transform="translate(-20.5625,22.9172) rotate(-90)">
+ <title>Sheet.44</title>
+ <path d="M0 63.32 L22.68 63.32" class="st1"/>
+ </g>
+ <g id="shape45-114" v:mID="45" v:groupContext="shape" transform="translate(347.941,22.9172) rotate(-90)">
+ <title>Sheet.45</title>
+ <path d="M0 63.32 L22.68 63.32" class="st1"/>
+ </g>
+ <g id="shape240-117" v:mID="240" v:groupContext="shape" transform="translate(326.224,-0.72)">
+ <title>Sheet.240</title>
+ <path d="M42.52 34.98 L28.35 63.32 L14.17 63.32 L0 34.98" class="st1"/>
+ </g>
+ <g id="shape36-120" v:mID="36" v:groupContext="shape" transform="translate(85.2794,-0.72)">
+ <title>Sheet.36</title>
+ <path d="M0 34.98 L325.98 34.98 L340.16 63.32 L379.84 63.32" class="st1"/>
+ </g>
+ <g id="shape241-123" v:mID="241" v:groupContext="shape" transform="translate(333.311,-0.72)">
+ <title>Sheet.241</title>
+ <desc>[P]</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)"/>
+ <v:textRect cx="14.1732" cy="49.149" width="28.35" height="28.3465"/>
+ <rect x="0" y="34.9757" width="28.3465" height="28.3465" class="st2"/>
+ <text x="9.28" y="51.55" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>[P]</text> </g>
+ <g id="shape242-126" v:mID="242" v:groupContext="shape" transform="translate(42.7597,-51.7436)">
+ <title>Sheet.242</title>
+ <desc>Frame</desc>
+ <v:textBlock v:margins="rect(4,4,4,4)" v:tabSpace="42.5197"/>
+ <v:textRect cx="184.252" cy="63.3222" width="368.51" height="0"/>
+ <path d="M7.92 63.32 L8.28 63.32 L360.22 63.32" class="st4"/>
+ <rect v:rectContext="textBkgnd" x="172.695" y="58.5223" width="23.1133" height="9.59985" class="st6"/>
+ <text x="172.7" y="65.72" class="st3" v:langID="1044"><v:paragraph v:horizAlign="1"/><v:tabList/>Frame</text> </g>
+ </g>
+</svg>
diff --git a/atmel-samd/asf/sam0/drivers/sercom/usart/usart.c b/atmel-samd/asf/sam0/drivers/sercom/usart/usart.c
new file mode 100644
index 000000000..e0abee9b8
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/usart/usart.c
@@ -0,0 +1,817 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM USART Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#include "usart.h"
+#include <pinmux.h>
+#if USART_CALLBACK_MODE == true
+# include "usart_interrupt.h"
+#endif
+
+/**
+ * \internal
+ * Set Configuration of the USART module
+ */
+static enum status_code _usart_set_config(
+ struct usart_module *const module,
+ const struct usart_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ /* Index for generic clock */
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+
+ /* Cache new register values to minimize the number of register writes */
+ uint32_t ctrla = 0;
+ uint32_t ctrlb = 0;
+#ifdef FEATURE_USART_ISO7816
+ uint32_t ctrlc = 0;
+#endif
+ uint16_t baud = 0;
+ uint32_t transfer_mode;
+
+ enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
+ enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
+
+#ifdef FEATURE_USART_OVER_SAMPLE
+ switch (config->sample_rate) {
+ case USART_SAMPLE_RATE_16X_ARITHMETIC:
+ mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
+ sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
+ break;
+ case USART_SAMPLE_RATE_8X_ARITHMETIC:
+ mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
+ sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
+ break;
+ case USART_SAMPLE_RATE_3X_ARITHMETIC:
+ mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
+ sample_num = SERCOM_ASYNC_SAMPLE_NUM_3;
+ break;
+ case USART_SAMPLE_RATE_16X_FRACTIONAL:
+ mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
+ sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
+ break;
+ case USART_SAMPLE_RATE_8X_FRACTIONAL:
+ mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
+ sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
+ break;
+ }
+#endif
+
+ /* Set data order, internal muxing, and clock polarity */
+ ctrla = (uint32_t)config->data_order |
+ (uint32_t)config->mux_setting |
+ #ifdef FEATURE_USART_OVER_SAMPLE
+ config->sample_adjustment |
+ config->sample_rate |
+ #endif
+ #ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
+ (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) |
+ #endif
+ (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
+
+ enum status_code status_code = STATUS_OK;
+
+ transfer_mode = (uint32_t)config->transfer_mode;
+#ifdef FEATURE_USART_ISO7816
+ if(config->iso7816_config.enabled) {
+ transfer_mode = config->iso7816_config.protocol_t;
+ }
+#endif
+ /* Get baud value from mode and clock */
+#ifdef FEATURE_USART_ISO7816
+ if(config->iso7816_config.enabled) {
+ baud = config->baudrate;
+ } else {
+#endif
+ switch (transfer_mode)
+ {
+ case USART_TRANSFER_SYNCHRONOUSLY:
+ if (!config->use_external_clock) {
+ status_code = _sercom_get_sync_baud_val(config->baudrate,
+ system_gclk_chan_get_hz(gclk_index), &baud);
+ }
+
+ break;
+
+ case USART_TRANSFER_ASYNCHRONOUSLY:
+ if (config->use_external_clock) {
+ status_code =
+ _sercom_get_async_baud_val(config->baudrate,
+ config->ext_clock_freq, &baud, mode, sample_num);
+ } else {
+ status_code =
+ _sercom_get_async_baud_val(config->baudrate,
+ system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
+ }
+
+ break;
+ }
+
+ /* Check if calculating the baudrate failed */
+ if (status_code != STATUS_OK) {
+ /* Abort */
+ return status_code;
+ }
+#ifdef FEATURE_USART_ISO7816
+ }
+#endif
+
+#ifdef FEATURE_USART_IRDA
+ if(config->encoding_format_enable) {
+ usart_hw->RXPL.reg = config->receive_pulse_length;
+ }
+#endif
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /*Set baud val */
+ usart_hw->BAUD.reg = baud;
+
+ /* Set sample mode */
+ ctrla |= transfer_mode;
+
+ if (config->use_external_clock == false) {
+ ctrla |= SERCOM_USART_CTRLA_MODE(0x1);
+ }
+ else {
+ ctrla |= SERCOM_USART_CTRLA_MODE(0x0);
+ }
+
+ /* Set stopbits and enable transceivers */
+ ctrlb =
+ #ifdef FEATURE_USART_IRDA
+ (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) |
+ #endif
+ #ifdef FEATURE_USART_START_FRAME_DECTION
+ (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
+ #endif
+ #ifdef FEATURE_USART_COLLISION_DECTION
+ (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) |
+ #endif
+ (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
+ (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
+
+#ifdef FEATURE_USART_ISO7816
+ if(config->iso7816_config.enabled) {
+ ctrla |= SERCOM_USART_CTRLA_FORM(0x07);
+ if (config->iso7816_config.enable_inverse) {
+ ctrla |= SERCOM_USART_CTRLA_TXINV | SERCOM_USART_CTRLA_RXINV;
+ }
+ ctrlb |= USART_CHARACTER_SIZE_8BIT;
+
+ switch(config->iso7816_config.protocol_t) {
+ case ISO7816_PROTOCOL_T_0:
+ ctrlb |= (uint32_t)config->stopbits;
+ ctrlc |= SERCOM_USART_CTRLC_GTIME(config->iso7816_config.guard_time) | \
+ (config->iso7816_config.inhibit_nack) | \
+ (config->iso7816_config.successive_recv_nack) | \
+ SERCOM_USART_CTRLC_MAXITER(config->iso7816_config.max_iterations);
+ break;
+ case ISO7816_PROTOCOL_T_1:
+ ctrlb |= USART_STOPBITS_1;
+ break;
+ }
+ } else {
+#endif
+ ctrlb |= (uint32_t)config->character_size;
+ /* Check parity mode bits */
+ if (config->parity != USART_PARITY_NONE) {
+ ctrla |= SERCOM_USART_CTRLA_FORM(1);
+ ctrlb |= config->parity;
+ } else {
+#ifdef FEATURE_USART_LIN_SLAVE
+ if(config->lin_slave_enable) {
+ ctrla |= SERCOM_USART_CTRLA_FORM(0x4);
+ } else {
+ ctrla |= SERCOM_USART_CTRLA_FORM(0);
+ }
+#else
+ ctrla |= SERCOM_USART_CTRLA_FORM(0);
+#endif
+ }
+#ifdef FEATURE_USART_ISO7816
+ }
+#endif
+
+#ifdef FEATURE_USART_LIN_MASTER
+ usart_hw->CTRLC.reg = ((usart_hw->CTRLC.reg) & SERCOM_USART_CTRLC_GTIME_Msk)
+ | config->lin_header_delay
+ | config->lin_break_length;
+
+ if (config->lin_node != LIN_INVALID_MODE) {
+ ctrla &= ~(SERCOM_USART_CTRLA_FORM(0xf));
+ ctrla |= config->lin_node;
+ }
+#endif
+
+ /* Set whether module should run in standby. */
+ if (config->run_in_standby || system_is_debugger_present()) {
+ ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
+ }
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Write configuration to CTRLB */
+ usart_hw->CTRLB.reg = ctrlb;
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Write configuration to CTRLA */
+ usart_hw->CTRLA.reg = ctrla;
+
+#ifdef FEATURE_USART_RS485
+ if ((usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_FORM_Msk) != \
+ SERCOM_USART_CTRLA_FORM(0x07)) {
+ usart_hw->CTRLC.reg &= ~(SERCOM_USART_CTRLC_GTIME(0x7));
+ usart_hw->CTRLC.reg |= SERCOM_USART_CTRLC_GTIME(config->rs485_guard_time);
+ }
+#endif
+
+#ifdef FEATURE_USART_ISO7816
+ if(config->iso7816_config.enabled) {
+ _usart_wait_for_sync(module);
+ usart_hw->CTRLC.reg = ctrlc;
+ }
+#endif
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Initializes the device
+ *
+ * Initializes the USART device based on the setting specified in the
+ * configuration struct.
+ *
+ * \param[out] module Pointer to USART device
+ * \param[in] hw Pointer to USART hardware instance
+ * \param[in] config Pointer to configuration struct
+ *
+ * \return Status of the initialization.
+ *
+ * \retval STATUS_OK The initialization was successful
+ * \retval STATUS_BUSY The USART module is busy
+ * resetting
+ * \retval STATUS_ERR_DENIED The USART has not been disabled in
+ * advance of initialization
+ * \retval STATUS_ERR_INVALID_ARG The configuration struct contains
+ * invalid configuration
+ * \retval STATUS_ERR_ALREADY_INITIALIZED The SERCOM instance has already been
+ * initialized with different clock
+ * configuration
+ * \retval STATUS_ERR_BAUD_UNAVAILABLE The BAUD rate given by the
+ * configuration
+ * struct cannot be reached with
+ * the current clock configuration
+ */
+enum status_code usart_init(
+ struct usart_module *const module,
+ Sercom *const hw,
+ const struct usart_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(hw);
+ Assert(config);
+
+ enum status_code status_code = STATUS_OK;
+
+ /* Assign module pointer to software instance struct */
+ module->hw = hw;
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
+ uint32_t pm_index, gclk_index;
+#if (SAML22) || (SAMC20)
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#elif (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+ pm_index = MCLK_APBDMASK_SERCOM5_Pos;
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+ } else {
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#elif (SAMC21)
+ pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos;
+
+ if (sercom_index == 5){
+ gclk_index = SERCOM5_GCLK_ID_CORE;
+ } else {
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+ }
+#else
+ pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
+ gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
+#endif
+
+ if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
+ /* The module is busy resetting itself */
+ return STATUS_BUSY;
+ }
+
+ if (usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
+ /* Check the module is enabled */
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Turn on module in PM */
+#if (SAML21) || (SAMR30)
+ if (sercom_index == 5) {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index);
+ } else {
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+ }
+#else
+ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
+#endif
+
+ /* Set up the GCLK for the module */
+ struct system_gclk_chan_config gclk_chan_conf;
+ system_gclk_chan_get_config_defaults(&gclk_chan_conf);
+ gclk_chan_conf.source_generator = config->generator_source;
+ system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
+ system_gclk_chan_enable(gclk_index);
+ sercom_set_gclk_generator(config->generator_source, false);
+
+ /* Set character size */
+ module->character_size = config->character_size;
+
+ /* Set transmitter and receiver status */
+ module->receiver_enabled = config->receiver_enable;
+ module->transmitter_enabled = config->transmitter_enable;
+
+#ifdef FEATURE_USART_LIN_SLAVE
+ module->lin_slave_enabled = config->lin_slave_enable;
+#endif
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ module->start_frame_detection_enabled = config->start_frame_detection_enable;
+#endif
+#ifdef FEATURE_USART_ISO7816
+ module->iso7816_mode_enabled = config->iso7816_config.enabled;
+#endif
+ /* Set configuration according to the config struct */
+ status_code = _usart_set_config(module, config);
+ if(status_code != STATUS_OK) {
+ return status_code;
+ }
+
+ struct system_pinmux_config pin_conf;
+ system_pinmux_get_config_defaults(&pin_conf);
+ pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
+ pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
+
+ uint32_t pad_pinmuxes[] = {
+ config->pinmux_pad0, config->pinmux_pad1,
+ config->pinmux_pad2, config->pinmux_pad3
+ };
+
+ /* Configure the SERCOM pins according to the user configuration */
+ for (uint8_t pad = 0; pad < 4; pad++) {
+ uint32_t current_pinmux = pad_pinmuxes[pad];
+
+ if (current_pinmux == PINMUX_DEFAULT) {
+ current_pinmux = _sercom_get_default_pad(hw, pad);
+ }
+
+ if (current_pinmux != PINMUX_UNUSED) {
+ pin_conf.mux_position = current_pinmux & 0xFFFF;
+ system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
+ }
+ }
+
+#if USART_CALLBACK_MODE == true
+ /* Initialize parameters */
+ for (uint32_t i = 0; i < USART_CALLBACK_N; i++) {
+ module->callback[i] = NULL;
+ }
+
+ module->tx_buffer_ptr = NULL;
+ module->rx_buffer_ptr = NULL;
+ module->remaining_tx_buffer_length = 0x0000;
+ module->remaining_rx_buffer_length = 0x0000;
+ module->callback_reg_mask = 0x00;
+ module->callback_enable_mask = 0x00;
+ module->rx_status = STATUS_OK;
+ module->tx_status = STATUS_OK;
+
+ /* Set interrupt handler and register USART software module struct in
+ * look-up table */
+ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw);
+ _sercom_set_handler(instance_index, _usart_interrupt_handler);
+ _sercom_instances[instance_index] = module;
+#endif
+
+ return status_code;
+}
+
+/**
+ * \brief Transmit a character via the USART
+ *
+ * This blocking function will transmit a single character via the
+ * USART.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[in] tx_data Data to transfer
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If the operation was completed
+ * \retval STATUS_BUSY If the operation was not completed, due to the USART
+ * module being busy
+ * \retval STATUS_ERR_DENIED If the transmitter is not enabled
+ */
+enum status_code usart_write_wait(
+ struct usart_module *const module,
+ const uint16_t tx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ /* Check that the transmitter is enabled */
+ if (!(module->transmitter_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+#if USART_CALLBACK_MODE == true
+ /* Check if the USART is busy doing asynchronous operation. */
+ if (module->remaining_tx_buffer_length > 0) {
+ return STATUS_BUSY;
+ }
+
+#else
+ /* Check if USART is ready for new data */
+ if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {
+ /* Return error code */
+ return STATUS_BUSY;
+ }
+#endif
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Write data to USART module */
+ usart_hw->DATA.reg = tx_data;
+
+ while (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)) {
+ /* Wait until data is sent */
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Receive a character via the USART
+ *
+ * This blocking function will receive a character via the USART.
+ *
+ * \param[in] module Pointer to the software instance struct
+ * \param[out] rx_data Pointer to received data
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If the operation was completed
+ * \retval STATUS_BUSY If the operation was not completed,
+ * due to the USART module being busy
+ * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
+ * due to configuration mismatch between USART
+ * and the sender
+ * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
+ * due to the baudrate being too low or the
+ * system frequency being too high
+ * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due to
+ * data being corrupted
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ */
+enum status_code usart_read_wait(
+ struct usart_module *const module,
+ uint16_t *const rx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Error variable */
+ uint8_t error_code;
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ /* Check that the receiver is enabled */
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+#if USART_CALLBACK_MODE == true
+ /* Check if the USART is busy doing asynchronous operation. */
+ if (module->remaining_rx_buffer_length > 0) {
+ return STATUS_BUSY;
+ }
+#endif
+
+ /* Check if USART has new data */
+ if (!(usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)) {
+ /* Return error code */
+ return STATUS_BUSY;
+ }
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Read out the status code and mask away all but the 3 LSBs*/
+ error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
+
+ /* Check if an error has occurred during the receiving */
+ if (error_code) {
+ /* Check which error occurred */
+ if (error_code & SERCOM_USART_STATUS_FERR) {
+ /* Clear flag by writing a 1 to it and
+ * return with an error code */
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
+
+ return STATUS_ERR_BAD_FORMAT;
+ } else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
+ /* Clear flag by writing a 1 to it and
+ * return with an error code */
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
+
+ return STATUS_ERR_OVERFLOW;
+ } else if (error_code & SERCOM_USART_STATUS_PERR) {
+ /* Clear flag by writing a 1 to it and
+ * return with an error code */
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
+
+ return STATUS_ERR_BAD_DATA;
+ }
+#ifdef FEATURE_USART_LIN_SLAVE
+ else if (error_code & SERCOM_USART_STATUS_ISF) {
+ /* Clear flag by writing 1 to it and
+ * return with an error code */
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF;
+
+ return STATUS_ERR_PROTOCOL;
+ }
+#endif
+#ifdef FEATURE_USART_COLLISION_DECTION
+ else if (error_code & SERCOM_USART_STATUS_COLL) {
+ /* Clear flag by writing 1 to it
+ * return with an error code */
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL;
+
+ return STATUS_ERR_PACKET_COLLISION;
+ }
+#endif
+ }
+
+ /* Read data from USART module */
+ *rx_data = usart_hw->DATA.reg;
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Transmit a buffer of characters via the USART
+ *
+ * This blocking function will transmit a block of \c length characters
+ * via the USART.
+ *
+ * \note Using this function in combination with the interrupt (\c _job) functions is
+ * not recommended as it has no functionality to check if there is an
+ * ongoing interrupt driven operation running or not.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] tx_data Pointer to data to transmit
+ * \param[in] length Number of characters to transmit
+ *
+ * \note If using 9-bit data, the array that *tx_data point to should be defined
+ * as uint16_t array and should be casted to uint8_t* pointer. Because it
+ * is an address pointer, the highest byte is not discarded. For example:
+ * \code
+ #define TX_LEN 3
+ uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133};
+ usart_write_buffer_wait(&module, (uint8_t*)tx_buf, TX_LEN);
+ \endcode
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
+ * arguments
+ * \retval STATUS_ERR_TIMEOUT If operation was not completed, due to USART
+ * module timing out
+ * \retval STATUS_ERR_DENIED If the transmitter is not enabled
+ */
+enum status_code usart_write_buffer_wait(
+ struct usart_module *const module,
+ const uint8_t *tx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Check if the buffer length is valid */
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ /* Check that the transmitter is enabled */
+ if (!(module->transmitter_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ uint16_t tx_pos = 0;
+
+ /* Blocks while buffer is being transferred */
+ while (length--) {
+ /* Wait for the USART to be ready for new data and abort
+ * operation if it doesn't get ready within the timeout*/
+ for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
+ if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE) {
+ break;
+ } else if (i == USART_TIMEOUT) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+
+ /* Data to send is at least 8 bits long */
+ uint16_t data_to_send = tx_data[tx_pos++];
+
+ /* Check if the character size exceeds 8 bit */
+ if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
+ data_to_send |= (tx_data[tx_pos++] << 8);
+ }
+
+ /* Send the data through the USART module */
+ usart_write_wait(module, data_to_send);
+ }
+
+ /* Wait until Transmit is complete or timeout */
+ for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
+ if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {
+ break;
+ } else if (i == USART_TIMEOUT) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Receive a buffer of \c length characters via the USART
+ *
+ * This blocking function will receive a block of \c length characters
+ * via the USART.
+ *
+ * \note Using this function in combination with the interrupt (\c *_job)
+ * functions is not recommended as it has no functionality to check if
+ * there is an ongoing interrupt driven operation running or not.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[out] rx_data Pointer to receive buffer
+ * \param[in] length Number of characters to receive
+ *
+ * \note If using 9-bit data, the array that *rx_data point to should be defined
+ * as uint16_t array and should be casted to uint8_t* pointer. Because it
+ * is an address pointer, the highest byte is not discarded. For example:
+ * \code
+ #define RX_LEN 3
+ uint16_t rx_buf[RX_LEN] = {0x0,};
+ usart_read_buffer_wait(&module, (uint8_t*)rx_buf, RX_LEN);
+ \endcode
+ *
+ * \return Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to an
+ * invalid argument being supplied
+ * \retval STATUS_ERR_TIMEOUT If operation was not completed, due
+ * to USART module timing out
+ * \retval STATUS_ERR_BAD_FORMAT If the operation was not completed,
+ * due to a configuration mismatch
+ * between USART and the sender
+ * \retval STATUS_ERR_BAD_OVERFLOW If the operation was not completed,
+ * due to the baudrate being too low or the
+ * system frequency being too high
+ * \retval STATUS_ERR_BAD_DATA If the operation was not completed, due
+ * to data being corrupted
+ * \retval STATUS_ERR_DENIED If the receiver is not enabled
+ */
+enum status_code usart_read_buffer_wait(
+ struct usart_module *const module,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Check if the buffer length is valid */
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ /* Check that the receiver is enabled */
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ uint16_t rx_pos = 0;
+
+ /* Blocks while buffer is being received */
+ while (length--) {
+ /* Wait for the USART to have new data and abort operation if it
+ * doesn't get ready within the timeout*/
+ for (uint32_t i = 0; i <= USART_TIMEOUT; i++) {
+ if (usart_hw->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) {
+ break;
+ } else if (i == USART_TIMEOUT) {
+ return STATUS_ERR_TIMEOUT;
+ }
+ }
+
+ enum status_code retval;
+ uint16_t received_data = 0;
+
+ retval = usart_read_wait(module, &received_data);
+
+ if (retval != STATUS_OK) {
+ /* Overflow, abort */
+ return retval;
+ }
+
+ /* Read value will be at least 8-bits long */
+ rx_data[rx_pos++] = received_data;
+
+ /* If 9-bit data, write next received byte to the buffer */
+ if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
+ rx_data[rx_pos++] = (received_data >> 8);
+ }
+ }
+
+ return STATUS_OK;
+}
diff --git a/atmel-samd/asf/sam0/drivers/sercom/usart/usart.h b/atmel-samd/asf/sam0/drivers/sercom/usart/usart.h
new file mode 100644
index 000000000..ac79c1116
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/usart/usart.h
@@ -0,0 +1,1593 @@
+/**
+ *
+ * \file
+ *
+ * \brief SAM SERCOM USART Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#ifndef USART_H_INCLUDED
+#define USART_H_INCLUDED
+
+/**
+ * \defgroup asfdoc_sam0_sercom_usart_group SAM Serial USART (SERCOM USART) Driver
+ *
+ * This driver for Atmel&reg; | SMART ARM&reg;-based microcontrollers provides
+ * an interface for the configuration and management of the SERCOM module in
+ * its USART mode to transfer or receive USART data frames. The following driver
+ * API modes are covered by this manual:
+ *
+ * - Polled APIs
+ * \if USART_CALLBACK_MODE
+ * - Callback APIs
+ * \endif
+ *
+ * The following peripheral is used by this module:
+ * - SERCOM (Serial Communication Interface)
+ *
+ * The following devices can use this module:
+ * - Atmel | SMART SAM D20/D21
+ * - Atmel | SMART SAM R21
+ * - Atmel | SMART SAM D09/D10/D11
+ * - Atmel | SMART SAM D10/D11
+ * - Atmel | SMART SAM L21/L22
+ * - Atmel | SMART SAM DA1
+ * - Atmel | SMART SAM C20/C21
+ *
+ * The outline of this documentation is as follows:
+ * - \ref asfdoc_sam0_sercom_usart_prerequisites
+ * - \ref asfdoc_sam0_sercom_usart_overview
+ * - \ref asfdoc_sam0_sercom_usart_special_considerations
+ * - \ref asfdoc_sam0_sercom_usart_extra_info
+ * - \ref asfdoc_sam0_sercom_usart_examples
+ * - \ref asfdoc_sam0_sercom_usart_api_overview
+ *
+ * \section asfdoc_sam0_sercom_usart_prerequisites Prerequisites
+ *
+ * To use the USART you need to have a GCLK generator enabled and running
+ * that can be used as the SERCOM clock source. This can either be configured
+ * in conf_clocks.h or by using the system clock driver.
+ *
+ * \section asfdoc_sam0_sercom_usart_overview Module Overview
+ *
+ * This driver will use one (or more) SERCOM interface(s) in the system
+ * and configure it to run as a USART interface in either synchronous
+ * or asynchronous mode.
+ *
+ * \subsection asfdoc_sam0_sercom_usart_features Driver Feature Macro Definition
+ * <table>
+ * <tr>
+ * <th>Driver Feature Macro</th>
+ * <th>Supported devices</th>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_SYNC_SCHEME_V2</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_OVER_SAMPLE</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_HARDWARE_FLOW_CONTROL</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_IRDA</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_LIN_SLAVE</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_COLLISION_DECTION</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_START_FRAME_DECTION</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION</td>
+ * <td>SAM D21/R21/D09/D10/D11/L21/L22/DA1/C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_RS485</td>
+ * <td>SAM C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>FEATURE_USART_LIN_MASTER</td>
+ * <td>SAM L22/C20/C21</td>
+ * </tr>
+ * </table>
+ * \note The specific features are only available in the driver when the
+ * selected device supports those features.
+ *
+ * \subsection asfdoc_sam0_sercom_usart_overview_frame_format Frame Format
+ *
+ * Communication is based on frames, where the frame format can be customized
+ * to accommodate a wide range of standards. A frame consists of a start bit,
+ * a number of data bits, an optional parity bit for error detection as well
+ * as a configurable length stop bit(s) - see
+ * \ref asfdoc_sam0_sercom_usart_frame_diagram "the figure below".
+ * \ref asfdoc_sam0_sercom_usart_frame_params "The table below" shows the
+ * available parameters you can change in a frame.
+ *
+ * \anchor asfdoc_sam0_sercom_usart_frame_params
+ * <table>
+ * <caption>USART Frame Parameters</caption>
+ * <tr>
+ * <th>Parameter</th>
+ * <th>Options</th>
+ * </tr>
+ * <tr>
+ * <td>Start bit</td>
+ * <td>1</td>
+ * </tr>
+ * <tr>
+ * <td>Data bits</td>
+ * <td>5, 6, 7, 8, 9</td>
+ * </tr>
+ * <tr>
+ * <td>Parity bit</td>
+ * <td>None, Even, Odd</td>
+ * </tr>
+ * <tr>
+ * <td>Stop bits</td>
+ * <td>1, 2</td>
+ * </tr>
+ * </table>
+ *
+ * \anchor asfdoc_sam0_sercom_usart_frame_diagram
+ * \image html usart_frame.svg "USART Frame Overview" width=100%
+ *
+ * \subsection asfdoc_sam0_sercom_usart_overview_sync Synchronous Mode
+ *
+ * In synchronous mode a dedicated clock line is provided; either by the USART
+ * itself if in master mode, or by an external master if in slave mode.
+ * Maximum transmission speed is the same as the GCLK clocking the USART
+ * peripheral when in slave mode, and the GCLK divided by two if in
+ * master mode. In synchronous mode the interface needs three lines to
+ * communicate:
+ * - TX (Transmit pin)
+ * - RX (Receive pin)
+ * - XCK (Clock pin)
+ *
+ * \subsubsection asfdoc_sam0_sercom_usart_overview_sync_sampling Data Sampling
+ * In synchronous mode the data is sampled on either the rising or falling edge
+ * of the clock signal. This is configured by setting the clock polarity in the
+ * configuration struct.
+ *
+ * \subsection asfdoc_sam0_sercom_usart_overview_async Asynchronous Mode
+ *
+ * In asynchronous mode no dedicated clock line is used, and the communication
+ * is based on matching the clock speed on the transmitter and receiver. The
+ * clock is generated from the internal SERCOM baudrate generator, and the
+ * frames are synchronized by using the frame start bits. Maximum transmission
+ * speed is limited to the SERCOM GCLK divided by 16.
+ * In asynchronous mode the interface only needs two lines to communicate:
+ * - TX (Transmit pin)
+ * - RX (Receive pin)
+ *
+ * \subsubsection asfdoc_sam0_sercom_usart_overview_async_clock_matching Transmitter/receiver Clock Matching
+ *
+ * For successful transmit and receive using the asynchronous mode the receiver
+ * and transmitter clocks needs to be closely matched. When receiving a frame
+ * that does not match the selected baudrate closely enough the receiver will
+ * be unable to synchronize the frame(s), and garbage transmissions will
+ * result.
+ *
+ * \subsection asfdoc_sam0_sercom_usart_parity Parity
+ * Parity can be enabled to detect if a transmission was in error. This is done
+ * by counting the number of "1" bits in the frame. When using even parity the
+ * parity bit will be set if the total number of "1"s in the frame are an even
+ * number. If using odd parity the parity bit will be set if the total number
+ * of "1"s are odd.
+ *
+ * When receiving a character the receiver will count the number of "1"s in the
+ * frame and give an error if the received frame and parity bit disagree.
+ *
+ * \subsection asfdoc_sam0_sercom_usart_overview_pin_configuration GPIO Configuration
+ *
+ * The SERCOM module has four internal pads; the RX pin can be placed freely on
+ * any one of the four pads, and the TX and XCK pins have two predefined
+ * positions that can be selected as a pair. The pads can then be routed to an
+ * external GPIO pin using the normal pin multiplexing scheme on the SAM.
+ *
+ * \section asfdoc_sam0_sercom_usart_special_considerations Special Considerations
+ *
+ * \if USART_CALLBACK_MODE
+ * Never execute large portions of code in the callbacks. These
+ * are run from the interrupt routine, and thus having long callbacks will
+ * keep the processor in the interrupt handler for an equally long time.
+ * A common way to handle this is to use global flags signaling the
+ * main application that an interrupt event has happened, and only do the
+ * minimal needed processing in the callback.
+ * \else
+ * No special considerations.
+ * \endif
+ *
+ * \section asfdoc_sam0_sercom_usart_extra_info Extra Information
+ *
+ * For extra information, see \ref asfdoc_sam0_sercom_usart_extra. This includes:
+ * - \ref asfdoc_sam0_sercom_usart_extra_acronyms
+ * - \ref asfdoc_sam0_sercom_usart_extra_dependencies
+ * - \ref asfdoc_sam0_sercom_usart_extra_errata
+ * - \ref asfdoc_sam0_sercom_usart_extra_history
+ *
+ * \section asfdoc_sam0_sercom_usart_examples Examples
+ *
+ * For a list of examples related to this driver, see
+ * \ref asfdoc_sam0_sercom_usart_exqsg.
+ *
+ * \section asfdoc_sam0_sercom_usart_api_overview API Overview
+ * @{
+ */
+
+#include <compiler.h>
+#include <sercom.h>
+#include <pinmux.h>
+
+#if USART_CALLBACK_MODE == true
+# include <sercom_interrupt.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \name Driver Feature Definition
+ * Define SERCOM USART features set according to different device family.
+ * @{
+ */
+#if (SAMD21) || (SAMR21) || (SAMD09) || (SAMD10) || (SAMD11) || (SAML21) || \
+ (SAML22) ||(SAMDA1) || (SAMC20) || (SAMC21) || (SAMR30) || defined(__DOXYGEN__)
+/** USART sync scheme version 2. */
+# define FEATURE_USART_SYNC_SCHEME_V2
+/** USART oversampling. */
+# define FEATURE_USART_OVER_SAMPLE
+/** USART hardware control flow. */
+# define FEATURE_USART_HARDWARE_FLOW_CONTROL
+/** IrDA mode. */
+# define FEATURE_USART_IRDA
+/** LIN slave mode. */
+# define FEATURE_USART_LIN_SLAVE
+/** USART collision detection. */
+# define FEATURE_USART_COLLISION_DECTION
+/** USART start frame detection. */
+# define FEATURE_USART_START_FRAME_DECTION
+/** USART start buffer overflow notification. */
+# define FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
+#endif
+
+#if (SAML22) || defined(__DOXYGEN__)
+/** ISO7816 for smart card interfacing. */
+#define FEATURE_USART_ISO7816
+#endif
+#if (SAMC20) || (SAMC21) || defined(__DOXYGEN__)
+/** LIN master mode. */
+#define FEATURE_USART_LIN_MASTER
+#endif
+#if (SAML22) || (SAMC20) || (SAMC21) || defined(__DOXYGEN__)
+/** RS485 mode. */
+# define FEATURE_USART_RS485
+#endif
+/*@}*/
+
+#ifdef FEATURE_USART_LIN_MASTER
+/**
+ * \brief LIN node type
+ *
+ * LIN node type.
+ */
+enum lin_node_type {
+ /** LIN master mode */
+ LIN_MASTER_NODE = SERCOM_USART_CTRLA_FORM(0x02),
+ /** LIN slave mode */
+ LIN_SLAVE_NODE = SERCOM_USART_CTRLA_FORM(0x04),
+ /** Neither LIN master nor LIN slave mode */
+ LIN_INVALID_MODE = SERCOM_USART_CTRLA_FORM(0x00),
+};
+
+/**
+ * \brief LIN master command enum
+ *
+ * LIN master command enum.
+ */
+enum lin_master_cmd {
+ /** LIN master software control transmission command */
+ LIN_MASTER_SOFTWARE_CONTROL_TRANSMIT_CMD = SERCOM_USART_CTRLB_LINCMD(0x01),
+ /** LIN master automatically transmission command */
+ LIN_MASTER_AUTO_TRANSMIT_CMD = SERCOM_USART_CTRLB_LINCMD(0x02),
+};
+
+/**
+ * \brief LIN master header delay
+ *
+ * LIN master header delay between break and sync transmission,
+ * and between the sync and identifier (ID) fields.
+ * This field is only valid when using automatically transmission command
+ */
+enum lin_master_header_delay {
+ /** Delay between break and sync transmission is 1 bit time.
+ Delay between sync and ID transmission is 1 bit time. */
+ LIN_MASTER_HEADER_DELAY_0 = SERCOM_USART_CTRLC_HDRDLY(0x0),
+ /** Delay between break and sync transmission is 4 bit time.
+ Delay between sync and ID transmission is 4 bit time. */
+ LIN_MASTER_HEADER_DELAY_1 = SERCOM_USART_CTRLC_HDRDLY(0x01),
+ /** Delay between break and sync transmission is 8 bit time.
+ Delay between sync and ID transmission is 4 bit time. */
+ LIN_MASTER_HEADER_DELAY_2 = SERCOM_USART_CTRLC_HDRDLY(0x02),
+ /** Delay between break and sync transmission is 14 bit time.
+ Delay between sync and ID transmission is 4 bit time. */
+ LIN_MASTER_HEADER_DELAY_3 = SERCOM_USART_CTRLC_HDRDLY(0x03),
+};
+
+/**
+ * \brief LIN master break length
+ *
+ * Length of the break field transmitted when in LIN master mode
+ */
+enum lin_master_break_length {
+ /** Break field transmission is 13 bit times */
+ LIN_MASTER_BREAK_LENGTH_13_BIT = SERCOM_USART_CTRLC_BRKLEN(0x0),
+ /** Break field transmission is 17 bit times */
+ LIN_MASTER_BREAK_LENGTH_17_BIT = SERCOM_USART_CTRLC_BRKLEN(0x1),
+ /** Break field transmission is 21 bit times */
+ LIN_MASTER_BREAK_LENGTH_21_BIT = SERCOM_USART_CTRLC_BRKLEN(0x2),
+ /** Break field transmission is 26 bit times */
+ LIN_MASTER_BREAK_LENGTH_26_BIT = SERCOM_USART_CTRLC_BRKLEN(0x3),
+};
+#endif
+#ifdef FEATURE_USART_ISO7816
+/**
+ * \brief ISO7816 protocol type
+ *
+ * ISO7816 protocol type.
+ */
+enum iso7816_protocol_type {
+ /** ISO7816 protocol type 0 */
+ ISO7816_PROTOCOL_T_0 = SERCOM_USART_CTRLA_CMODE,
+ /** ISO7816 protocol type 1 */
+ ISO7816_PROTOCOL_T_1 = (0x0ul << SERCOM_USART_CTRLA_CMODE_Pos),
+};
+
+/**
+ * \brief ISO7816 guard time
+ *
+ * The value of ISO7816 guard time.
+ */
+enum iso7816_guard_time {
+ /** The guard time is 2-bit times */
+ ISO7816_GUARD_TIME_2_BIT = 2,
+ /** The guard time is 3-bit times */
+ ISO7816_GUARD_TIME_3_BIT,
+ /** The guard time is 4-bit times */
+ ISO7816_GUARD_TIME_4_BIT,
+ /** The guard time is 5-bit times */
+ ISO7816_GUARD_TIME_5_BIT,
+ /** The guard time is 6-bit times */
+ ISO7816_GUARD_TIME_6_BIT,
+ /** The guard time is 7-bit times */
+ ISO7816_GUARD_TIME_7_BIT,
+};
+
+/**
+ * \brief ISO7816 receive NACK inhibit
+ *
+ * The value of ISO7816 receive NACK inhibit.
+ */
+enum iso7816_inhibit_nack {
+ /** The NACK is generated */
+ ISO7816_INHIBIT_NACK_DISABLE = (0x0ul << SERCOM_USART_CTRLC_INACK_Pos),
+ /** The NACK is not generated */
+ ISO7816_INHIBIT_NACK_ENABLE = SERCOM_USART_CTRLC_INACK,
+};
+
+/**
+ * \brief ISO7816 disable successive receive NACK
+ *
+ * The value of ISO7816 disable successive receive NACK.
+ */
+enum iso7816_successive_recv_nack {
+ /** The successive receive NACK is enable. */
+ ISO7816_SUCCESSIVE_RECV_NACK_DISABLE = (0x0ul << SERCOM_USART_CTRLC_INACK_Pos),
+ /** The successive receive NACK is disable. */
+ ISO7816_SUCCESSIVE_RECV_NACK_ENABLE = SERCOM_USART_CTRLC_DSNACK,
+};
+
+/**
+ * \brief ISO7816 configuration struct
+ *
+ * ISO7816 configuration structure.
+ */
+struct iso7816_config_t {
+ /* ISO7816 mode enable */
+ bool enabled;
+ /** ISO7816 protocol type */
+ enum iso7816_protocol_type protocol_t;
+ /** Enable inverse transmission and reception */
+ bool enable_inverse;
+ /** Guard time, which lasts two bit times */
+ enum iso7816_guard_time guard_time;
+ /**
+ * Inhibit Non Acknowledge:
+ * - 0: the NACK is generated;
+ * - 1: the NACK is not generated.
+ */
+ enum iso7816_inhibit_nack inhibit_nack;
+ /**
+ * Disable successive NACKs.
+ * - 0: NACK is sent on the ISO line as soon as a parity error occurs
+ * in the received character. Successive parity errors are counted up to
+ * the value in the max_iterations field. These parity errors generate
+ * a NACK on the ISO line. As soon as this value is reached, no additional
+ * NACK is sent on the ISO line. The ITERATION flag is asserted.
+ */
+ enum iso7816_successive_recv_nack successive_recv_nack;
+ /* Max number of repetitions */
+ uint32_t max_iterations;
+};
+#endif
+
+#ifndef PINMUX_DEFAULT
+/** Default pinmux */
+# define PINMUX_DEFAULT 0
+#endif
+
+#ifndef PINMUX_UNUSED
+/** Unused pinmux */
+# define PINMUX_UNUSED 0xFFFFFFFF
+#endif
+
+#ifndef USART_TIMEOUT
+/** USART timeout value */
+# define USART_TIMEOUT 0xFFFF
+#endif
+
+#if USART_CALLBACK_MODE == true
+/**
+ * \brief USART callback enum
+ *
+ * Callbacks for the Asynchronous USART driver.
+ */
+enum usart_callback {
+ /** Callback for buffer transmitted */
+ USART_CALLBACK_BUFFER_TRANSMITTED,
+ /** Callback for buffer received */
+ USART_CALLBACK_BUFFER_RECEIVED,
+ /** Callback for error */
+ USART_CALLBACK_ERROR,
+#ifdef FEATURE_USART_LIN_SLAVE
+ /** Callback for break character is received */
+ USART_CALLBACK_BREAK_RECEIVED,
+#endif
+#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
+ /** Callback for a change is detected on the CTS pin */
+ USART_CALLBACK_CTS_INPUT_CHANGE,
+#endif
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ /** Callback for a start condition is detected on the RxD line */
+ USART_CALLBACK_START_RECEIVED,
+#endif
+# if !defined(__DOXYGEN__)
+ /** Number of available callbacks */
+ USART_CALLBACK_N,
+# endif
+};
+#endif
+
+/**
+ * \brief USART Data Order enum
+ *
+ * The data order decides which MSB or LSB is shifted out first when data is
+ * transferred.
+ */
+enum usart_dataorder {
+ /** The MSB will be shifted out first during transmission,
+ * and shifted in first during reception */
+ USART_DATAORDER_MSB = 0,
+ /** The LSB will be shifted out first during transmission,
+ * and shifted in first during reception */
+ USART_DATAORDER_LSB = SERCOM_USART_CTRLA_DORD,
+};
+
+/**
+ * \brief USART Transfer mode enum
+ *
+ * Select USART transfer mode.
+ */
+enum usart_transfer_mode {
+ /** Transfer of data is done synchronously */
+ USART_TRANSFER_SYNCHRONOUSLY = (SERCOM_USART_CTRLA_CMODE),
+ /** Transfer of data is done asynchronously */
+ USART_TRANSFER_ASYNCHRONOUSLY = (0x0ul << SERCOM_USART_CTRLA_CMODE_Pos),
+};
+
+/**
+ * \brief USART Parity enum
+ *
+ * Select parity USART parity mode.
+ */
+enum usart_parity {
+ /** For odd parity checking, the parity bit will be set if number of
+ * ones being transferred is even */
+ USART_PARITY_ODD = SERCOM_USART_CTRLB_PMODE,
+
+ /** For even parity checking, the parity bit will be set if number of
+ * ones being received is odd */
+ USART_PARITY_EVEN = 0,
+
+ /** No parity checking will be executed, and there will be no parity bit
+ * in the received frame */
+ USART_PARITY_NONE = 0xFF,
+};
+
+/**
+ * \brief USART signal MUX settings
+ *
+ * Set the functionality of the SERCOM pins.
+ *
+ * See \ref asfdoc_sam0_sercom_usart_mux_settings for a description of the
+ * various MUX setting options.
+ */
+enum usart_signal_mux_settings {
+#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
+ /** MUX setting RX_0_TX_0_XCK_1 */
+ USART_RX_0_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(0)),
+ /** MUX setting RX_0_TX_2_XCK_3 */
+ USART_RX_0_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(1)),
+ /** MUX setting USART_RX_0_TX_0_RTS_2_CTS_3 */
+ USART_RX_0_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(2)),
+ /** MUX setting RX_1_TX_0_XCK_1 */
+ USART_RX_1_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(0)),
+ /** MUX setting RX_1_TX_2_XCK_3 */
+ USART_RX_1_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(1)),
+ /** MUX setting USART_RX_1_TX_0_RTS_2_CTS_3 */
+ USART_RX_1_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(2)),
+ /** MUX setting RX_2_TX_0_XCK_1 */
+ USART_RX_2_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(0)),
+ /** MUX setting RX_2_TX_2_XCK_3 */
+ USART_RX_2_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(1)),
+ /** MUX setting USART_RX_2_TX_0_RTS_2_CTS_3 */
+ USART_RX_2_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(2)),
+ /** MUX setting RX_3_TX_0_XCK_1 */
+ USART_RX_3_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(0)),
+ /** MUX setting RX_3_TX_2_XCK_3 */
+ USART_RX_3_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(1)),
+ /** MUX setting USART_RX_3_TX_0_RTS_2_CTS_3 */
+ USART_RX_3_TX_0_RTS_2_CTS_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(2)),
+#ifdef FEATURE_USART_RS485
+ /** MUX setting USART_RX_0_TX_0_XCK_1_TE_2 */
+ USART_RX_0_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO(3)),
+ /** MUX setting USART_RX_1_TX_0_XCK_1_TE_2 */
+ USART_RX_1_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO(3)),
+ /** MUX setting USART_RX_2_TX_0_XCK_1_TE_2 */
+ USART_RX_2_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO(3)),
+ /** MUX setting USART_RX_3_TX_0_XCK_1_TE_2 */
+ USART_RX_3_TX_0_XCK_1_TE_2 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO(3)),
+#endif
+#else
+ /** MUX setting RX_0_TX_0_XCK_1 */
+ USART_RX_0_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(0)),
+ /** MUX setting RX_0_TX_2_XCK_3 */
+ USART_RX_0_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(0) | SERCOM_USART_CTRLA_TXPO),
+ /** MUX setting RX_1_TX_0_XCK_1 */
+ USART_RX_1_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(1)),
+ /** MUX setting RX_1_TX_2_XCK_3 */
+ USART_RX_1_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(1) | SERCOM_USART_CTRLA_TXPO),
+ /** MUX setting RX_2_TX_0_XCK_1 */
+ USART_RX_2_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(2)),
+ /** MUX setting RX_2_TX_2_XCK_3 */
+ USART_RX_2_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(2) | SERCOM_USART_CTRLA_TXPO),
+ /** MUX setting RX_3_TX_0_XCK_1 */
+ USART_RX_3_TX_0_XCK_1 = (SERCOM_USART_CTRLA_RXPO(3)),
+ /** MUX setting RX_3_TX_2_XCK_3 */
+ USART_RX_3_TX_2_XCK_3 = (SERCOM_USART_CTRLA_RXPO(3) | SERCOM_USART_CTRLA_TXPO),
+#endif
+};
+
+/**
+ * \brief USART Stop Bits enum
+ *
+ * Number of stop bits for a frame.
+ */
+enum usart_stopbits {
+ /** Each transferred frame contains one stop bit */
+ USART_STOPBITS_1 = 0,
+ /** Each transferred frame contains two stop bits */
+ USART_STOPBITS_2 = SERCOM_USART_CTRLB_SBMODE,
+};
+
+/**
+ * \brief USART Character Size
+ *
+ * Number of bits for the character sent in a frame.
+ */
+enum usart_character_size {
+ /** The char being sent in a frame is five bits long */
+ USART_CHARACTER_SIZE_5BIT = SERCOM_USART_CTRLB_CHSIZE(5),
+ /** The char being sent in a frame is six bits long */
+ USART_CHARACTER_SIZE_6BIT = SERCOM_USART_CTRLB_CHSIZE(6),
+ /** The char being sent in a frame is seven bits long */
+ USART_CHARACTER_SIZE_7BIT = SERCOM_USART_CTRLB_CHSIZE(7),
+ /** The char being sent in a frame is eight bits long */
+ USART_CHARACTER_SIZE_8BIT = SERCOM_USART_CTRLB_CHSIZE(0),
+ /** The char being sent in a frame is nine bits long */
+ USART_CHARACTER_SIZE_9BIT = SERCOM_USART_CTRLB_CHSIZE(1),
+};
+
+#ifdef FEATURE_USART_OVER_SAMPLE
+/**
+ * \brief USART Sample Rate
+ *
+ * The value of sample rate and baudrate generation mode.
+ */
+enum usart_sample_rate {
+ /** 16x over-sampling using arithmetic baudrate generation */
+ USART_SAMPLE_RATE_16X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(0),
+ /** 16x over-sampling using fractional baudrate generation */
+ USART_SAMPLE_RATE_16X_FRACTIONAL = SERCOM_USART_CTRLA_SAMPR(1),
+ /** 8x over-sampling using arithmetic baudrate generation */
+ USART_SAMPLE_RATE_8X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(2),
+ /** 8x over-sampling using fractional baudrate generation */
+ USART_SAMPLE_RATE_8X_FRACTIONAL = SERCOM_USART_CTRLA_SAMPR(3),
+ /** 3x over-sampling using arithmetic baudrate generation */
+ USART_SAMPLE_RATE_3X_ARITHMETIC = SERCOM_USART_CTRLA_SAMPR(4),
+};
+
+/**
+ * \brief USART Sample Adjustment
+ *
+ * The value of sample number used for majority voting.
+ */
+enum usart_sample_adjustment {
+ /** The first, middle and last sample number used for majority voting is 7-8-9 */
+ USART_SAMPLE_ADJUSTMENT_7_8_9 = SERCOM_USART_CTRLA_SAMPA(0),
+ /** The first, middle and last sample number used for majority voting is 9-10-11 */
+ USART_SAMPLE_ADJUSTMENT_9_10_11 = SERCOM_USART_CTRLA_SAMPA(1),
+ /** The first, middle and last sample number used for majority voting is 11-12-13 */
+ USART_SAMPLE_ADJUSTMENT_11_12_13 = SERCOM_USART_CTRLA_SAMPA(2),
+ /** The first, middle and last sample number used for majority voting is 13-14-15 */
+ USART_SAMPLE_ADJUSTMENT_13_14_15 = SERCOM_USART_CTRLA_SAMPA(3),
+};
+#endif
+
+#ifdef FEATURE_USART_RS485
+/**
+ * \brief RS485 Guard Time
+ *
+ * The value of RS485 guard time.
+ */
+enum rs485_guard_time {
+ /** The guard time is 0-bit time */
+ RS485_GUARD_TIME_0_BIT = 0,
+ /** The guard time is 1-bit time */
+ RS485_GUARD_TIME_1_BIT,
+ /** The guard time is 2-bit times */
+ RS485_GUARD_TIME_2_BIT,
+ /** The guard time is 3-bit times */
+ RS485_GUARD_TIME_3_BIT,
+ /** The guard time is 4-bit times */
+ RS485_GUARD_TIME_4_BIT,
+ /** The guard time is 5-bit times */
+ RS485_GUARD_TIME_5_BIT,
+ /** The guard time is 6-bit times */
+ RS485_GUARD_TIME_6_BIT,
+ /** The guard time is 7-bit times */
+ RS485_GUARD_TIME_7_BIT,
+};
+#endif
+
+/**
+ * \brief USART Transceiver
+ *
+ * Select Receiver or Transmitter.
+ */
+enum usart_transceiver_type {
+ /** The parameter is for the Receiver */
+ USART_TRANSCEIVER_RX,
+ /** The parameter is for the Transmitter */
+ USART_TRANSCEIVER_TX,
+};
+
+/**
+ * \brief USART configuration struct
+ *
+ * Configuration options for USART.
+ */
+struct usart_config {
+ /** USART bit order (MSB or LSB first) */
+ enum usart_dataorder data_order;
+ /** USART in asynchronous or synchronous mode */
+ enum usart_transfer_mode transfer_mode;
+ /** USART parity */
+ enum usart_parity parity;
+ /** Number of stop bits */
+ enum usart_stopbits stopbits;
+ /** USART character size */
+ enum usart_character_size character_size;
+ /** USART pin out */
+ enum usart_signal_mux_settings mux_setting;
+#ifdef FEATURE_USART_OVER_SAMPLE
+ /** USART sample rate */
+ enum usart_sample_rate sample_rate;
+ /** USART sample adjustment */
+ enum usart_sample_adjustment sample_adjustment;
+#endif
+#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
+ /** Controls when the buffer overflow status bit is asserted when a buffer overflow occurs */
+ bool immediate_buffer_overflow_notification;
+#endif
+#ifdef FEATURE_USART_IRDA
+ /** Enable IrDA encoding format */
+ bool encoding_format_enable;
+ /** The minimum pulse length required for a pulse to be accepted by the IrDA receiver */
+ uint8_t receive_pulse_length;
+#endif
+#ifdef FEATURE_USART_LIN_SLAVE
+ /** Enable LIN Slave Support */
+ bool lin_slave_enable;
+#endif
+
+#ifdef FEATURE_USART_LIN_MASTER
+ /** LIN node type */
+ enum lin_node_type lin_node;
+ /** LIN master header delay */
+ enum lin_master_header_delay lin_header_delay;
+ /** LIN Master Break Length */
+ enum lin_master_break_length lin_break_length;
+#endif
+
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ /** Enable start of frame dection */
+ bool start_frame_detection_enable;
+#endif
+#ifdef FEATURE_USART_ISO7816
+ /** Enable ISO7816 for smart card interfacing */
+ struct iso7816_config_t iso7816_config;
+#endif
+#ifdef FEATURE_USART_RS485
+ /** RS485 guard time */
+ enum rs485_guard_time rs485_guard_time;
+#endif
+#ifdef FEATURE_USART_COLLISION_DECTION
+ /** Enable collision dection */
+ bool collision_detection_enable;
+#endif
+ /** USART baudrate */
+ uint32_t baudrate;
+ /** Enable receiver */
+ bool receiver_enable;
+ /** Enable transmitter */
+ bool transmitter_enable;
+
+ /** USART Clock Polarity.
+ * If true, data changes on falling XCK edge and
+ * is sampled at rising edge.
+ * If false, data changes on rising XCK edge and
+ * is sampled at falling edge.
+ * */
+ bool clock_polarity_inverted;
+
+ /** States whether to use the external clock applied to the XCK pin.
+ * In synchronous mode the shift register will act directly on the XCK clock.
+ * In asynchronous mode the XCK will be the input to the USART hardware module.
+ */
+ bool use_external_clock;
+ /** External clock frequency in synchronous mode.
+ * This must be set if \c use_external_clock is true. */
+ uint32_t ext_clock_freq;
+ /** If true the USART will be kept running in Standby sleep mode */
+ bool run_in_standby;
+ /** GCLK generator source */
+ enum gclk_generator generator_source;
+ /** PAD0 pinmux.
+ *
+ * If current USARTx has several alternative multiplexing I/O pins for PAD0, then
+ * only one peripheral multiplexing I/O can be enabled for current USARTx PAD0
+ * function. Make sure that no other alternative multiplexing I/O is associated
+ * with the same USARTx PAD0.
+ */
+ uint32_t pinmux_pad0;
+ /** PAD1 pinmux.
+ *
+ * If current USARTx has several alternative multiplexing I/O pins for PAD1, then
+ * only one peripheral multiplexing I/O can be enabled for current USARTx PAD1
+ * function. Make sure that no other alternative multiplexing I/O is associated
+ * with the same USARTx PAD1.
+ */
+ uint32_t pinmux_pad1;
+ /** PAD2 pinmux.
+ *
+ * If current USARTx has several alternative multiplexing I/O pins for PAD2, then
+ * only one peripheral multiplexing I/O can be enabled for current USARTx PAD2
+ * function. Make sure that no other alternative multiplexing I/O is associated
+ * with the same USARTx PAD2.
+ */
+ uint32_t pinmux_pad2;
+ /** PAD3 pinmux.
+ *
+ * If current USARTx has several alternative multiplexing I/O pins for PAD3, then
+ * only one peripheral multiplexing I/O can be enabled for current USARTx PAD3
+ * function. Make sure that no other alternative multiplexing I/O is associated
+ * with the same USARTx PAD3.
+ */
+ uint32_t pinmux_pad3;
+};
+
+#if USART_CALLBACK_MODE == true
+/**
+ * \brief USART module instance
+ *
+ * Forward Declaration for the device instance.
+ */
+struct usart_module;
+
+/**
+ * \brief USART callback type
+ *
+ * Type of the callback functions.
+ */
+typedef void (*usart_callback_t)(struct usart_module *const module);
+#endif
+
+/**
+ * \brief SERCOM USART driver software device instance structure.
+ *
+ * SERCOM USART driver software instance structure, used to retain software
+ * state information of an associated hardware module instance.
+ *
+ * \note The fields of this structure should not be altered by the user
+ * application; they are reserved for module-internal use only.
+ */
+struct usart_module {
+#if !defined(__DOXYGEN__)
+ /** Pointer to the hardware instance */
+ Sercom *hw;
+ /** Module lock */
+ volatile bool locked;
+ /** Character size of the data being transferred */
+ enum usart_character_size character_size;
+ /** Receiver enabled */
+ bool receiver_enabled;
+ /** Transmitter enabled */
+ bool transmitter_enabled;
+#ifdef FEATURE_USART_LIN_SLAVE
+ /** LIN Slave Support enabled */
+ bool lin_slave_enabled;
+#endif
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ /** Start of frame dection enabled */
+ bool start_frame_detection_enabled;
+#endif
+#ifdef FEATURE_USART_ISO7816
+ /** ISO7816 mode enable */
+ bool iso7816_mode_enabled;
+#endif
+# if USART_CALLBACK_MODE == true
+ /** Array to store callback function pointers in */
+ usart_callback_t callback[USART_CALLBACK_N];
+ /** Buffer pointer to where the next received character will be put */
+ volatile uint8_t *rx_buffer_ptr;
+
+ /** Buffer pointer to where the next character will be transmitted from
+ **/
+ volatile uint8_t *tx_buffer_ptr;
+ /** Remaining characters to receive */
+ volatile uint16_t remaining_rx_buffer_length;
+ /** Remaining characters to transmit */
+ volatile uint16_t remaining_tx_buffer_length;
+ /** Bit mask for callbacks registered */
+ uint8_t callback_reg_mask;
+ /** Bit mask for callbacks enabled */
+ uint8_t callback_enable_mask;
+ /** Holds the status of the ongoing or last read operation */
+ volatile enum status_code rx_status;
+ /** Holds the status of the ongoing or last write operation */
+ volatile enum status_code tx_status;
+# endif
+#endif
+};
+
+ /**
+ * \name Lock/Unlock
+ * @{
+ */
+
+/**
+ * \brief Attempt to get lock on driver instance
+ *
+ * This function checks the instance's lock, which indicates whether or not it
+ * is currently in use, and sets the lock if it was not already set.
+ *
+ * The purpose of this is to enable exclusive access to driver instances, so
+ * that, e.g., transactions by different services will not interfere with each
+ * other.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ * \retval STATUS_OK If the module was locked
+ * \retval STATUS_BUSY If the module was already locked
+ */
+static inline enum status_code usart_lock(
+ struct usart_module *const module)
+{
+ enum status_code status;
+
+ system_interrupt_enter_critical_section();
+
+ if (module->locked) {
+ status = STATUS_BUSY;
+ } else {
+ module->locked = true;
+ status = STATUS_OK;
+ }
+
+ system_interrupt_leave_critical_section();
+
+ return status;
+}
+
+/**
+ * \brief Unlock driver instance
+ *
+ * This function clears the instance lock, indicating that it is available for
+ * use.
+ *
+ * \param[in,out] module Pointer to the driver instance to lock
+ *
+ */
+static inline void usart_unlock(struct usart_module *const module)
+{
+ module->locked = false;
+}
+
+/** @} */
+
+/**
+ * \brief Check if peripheral is busy syncing registers across clock domains
+ *
+ * Return peripheral synchronization status. If doing a non-blocking
+ * implementation this function can be used to check the sync state and hold of
+ * any new actions until sync is complete. If this function is not run; the
+ * functions will block until the sync has completed.
+ *
+ * \param[in] module Pointer to peripheral module
+ *
+ * \return Peripheral sync status.
+ *
+ * \retval true Peripheral is busy syncing
+ * \retval false Peripheral is not busy syncing and can be read/written without
+ * stalling the bus
+ */
+static inline bool usart_is_syncing(
+ const struct usart_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+#ifdef FEATURE_USART_SYNC_SCHEME_V2
+ return (usart_hw->SYNCBUSY.reg);
+#else
+ return (usart_hw->STATUS.reg & SERCOM_USART_STATUS_SYNCBUSY);
+#endif
+}
+
+#if !defined (__DOXYGEN__)
+/**
+ * \internal
+ * Waits until synchronization is complete
+ */
+static inline void _usart_wait_for_sync(
+ const struct usart_module *const module)
+{
+ /* Sanity check */
+ Assert(module);
+
+ while (usart_is_syncing(module)) {
+ /* Wait until the synchronization is complete */
+ }
+}
+#endif
+
+/**
+ * \brief Initializes the device to predefined defaults
+ *
+ * Initialize the USART device to predefined defaults:
+ * - 8-bit asynchronous USART
+ * - No parity
+ * - One stop bit
+ * - 9600 baud
+ * - Transmitter enabled
+ * - Receiver enabled
+ * - GCLK generator 0 as clock source
+ * - Default pin configuration
+ *
+ * The configuration struct will be updated with the default
+ * configuration.
+ *
+ * \param[in,out] config Pointer to configuration struct
+ */
+static inline void usart_get_config_defaults(
+ struct usart_config *const config)
+{
+ /* Sanity check arguments */
+ Assert(config);
+
+ /* Set default config in the config struct */
+ config->data_order = USART_DATAORDER_LSB;
+ config->transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY;
+ config->parity = USART_PARITY_NONE;
+ config->stopbits = USART_STOPBITS_1;
+ config->character_size = USART_CHARACTER_SIZE_8BIT;
+ config->baudrate = 9600;
+ config->receiver_enable = true;
+ config->transmitter_enable = true;
+ config->clock_polarity_inverted = false;
+ config->use_external_clock = false;
+ config->ext_clock_freq = 0;
+ config->mux_setting = USART_RX_1_TX_2_XCK_3;
+ config->run_in_standby = false;
+ config->generator_source = GCLK_GENERATOR_0;
+ config->pinmux_pad0 = PINMUX_DEFAULT;
+ config->pinmux_pad1 = PINMUX_DEFAULT;
+ config->pinmux_pad2 = PINMUX_DEFAULT;
+ config->pinmux_pad3 = PINMUX_DEFAULT;
+#ifdef FEATURE_USART_OVER_SAMPLE
+ config->sample_adjustment = USART_SAMPLE_ADJUSTMENT_7_8_9;
+ config->sample_rate = USART_SAMPLE_RATE_16X_ARITHMETIC;
+#endif
+#ifdef FEATURE_USART_LIN_SLAVE
+ config->lin_slave_enable = false;
+#endif
+
+#ifdef FEATURE_USART_LIN_MASTER
+ config->lin_node = LIN_INVALID_MODE;
+ config->lin_header_delay = LIN_MASTER_HEADER_DELAY_0;
+ config->lin_break_length = LIN_MASTER_BREAK_LENGTH_13_BIT;
+#endif
+
+#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
+ config->immediate_buffer_overflow_notification = false;
+#endif
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ config->start_frame_detection_enable = false;
+#endif
+#ifdef FEATURE_USART_IRDA
+ config->encoding_format_enable = false;
+ config->receive_pulse_length = 19;
+#endif
+#ifdef FEATURE_USART_ISO7816
+ config->iso7816_config.enabled = false;
+ config->iso7816_config.guard_time = ISO7816_GUARD_TIME_2_BIT;
+ config->iso7816_config.protocol_t = ISO7816_PROTOCOL_T_0;
+ config->iso7816_config.enable_inverse = false;
+ config->iso7816_config.inhibit_nack = ISO7816_INHIBIT_NACK_DISABLE;
+ config->iso7816_config.successive_recv_nack = ISO7816_SUCCESSIVE_RECV_NACK_DISABLE;
+ config->iso7816_config.max_iterations = 7;
+#endif
+#ifdef FEATURE_USART_COLLISION_DECTION
+ config->collision_detection_enable = false;
+#endif
+#ifdef FEATURE_USART_RS485
+ config->rs485_guard_time = RS485_GUARD_TIME_0_BIT;
+#endif
+}
+
+enum status_code usart_init(
+ struct usart_module *const module,
+ Sercom *const hw,
+ const struct usart_config *const config);
+
+/**
+ * \brief Enable the module
+ *
+ * Enables the USART module.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ */
+static inline void usart_enable(
+ const struct usart_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+#if USART_CALLBACK_MODE == true
+ /* Enable Global interrupt for module */
+ system_interrupt_enable(_sercom_get_interrupt_vector(module->hw));
+#endif
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Enable USART module */
+ usart_hw->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
+}
+
+/**
+ * \brief Disable module
+ *
+ * Disables the USART module.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ */
+static inline void usart_disable(
+ const struct usart_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+#if USART_CALLBACK_MODE == true
+ /* Disable Global interrupt for module */
+ system_interrupt_disable(_sercom_get_interrupt_vector(module->hw));
+#endif
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Disable USART module */
+ usart_hw->CTRLA.reg &= ~SERCOM_USART_CTRLA_ENABLE;
+}
+
+/**
+ * \brief Resets the USART module
+ *
+ * Disables and resets the USART module.
+ *
+ * \param[in] module Pointer to the USART software instance struct
+ */
+static inline void usart_reset(
+ const struct usart_module *const module)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ usart_disable(module);
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ /* Reset module */
+ usart_hw->CTRLA.reg = SERCOM_USART_CTRLA_SWRST;
+}
+
+/**
+ * \name Writing and Reading
+ * @{
+ */
+enum status_code usart_write_wait(
+ struct usart_module *const module,
+ const uint16_t tx_data);
+
+enum status_code usart_read_wait(
+ struct usart_module *const module,
+ uint16_t *const rx_data);
+
+enum status_code usart_write_buffer_wait(
+ struct usart_module *const module,
+ const uint8_t *tx_data,
+ uint16_t length);
+
+enum status_code usart_read_buffer_wait(
+ struct usart_module *const module,
+ uint8_t *rx_data,
+ uint16_t length);
+/** @} */
+
+/**
+ * \name Enabling/Disabling Receiver and Transmitter
+ * @{
+ */
+
+/**
+ * \brief Enable Transceiver
+ *
+ * Enable the given transceiver. Either RX or TX.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] transceiver_type Transceiver type
+ */
+static inline void usart_enable_transceiver(
+ struct usart_module *const module,
+ enum usart_transceiver_type transceiver_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ switch (transceiver_type) {
+ case USART_TRANSCEIVER_RX:
+ /* Enable RX */
+ usart_hw->CTRLB.reg |= SERCOM_USART_CTRLB_RXEN;
+ module->receiver_enabled = true;
+ break;
+
+ case USART_TRANSCEIVER_TX:
+ /* Enable TX */
+ usart_hw->CTRLB.reg |= SERCOM_USART_CTRLB_TXEN;
+ module->transmitter_enabled = true;
+ break;
+ }
+ _usart_wait_for_sync(module);
+}
+
+/**
+ * \brief Disable Transceiver
+ *
+ * Disable the given transceiver (RX or TX).
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] transceiver_type Transceiver type
+ */
+static inline void usart_disable_transceiver(
+ struct usart_module *const module,
+ enum usart_transceiver_type transceiver_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ /* Wait until synchronization is complete */
+ _usart_wait_for_sync(module);
+
+ switch (transceiver_type) {
+ case USART_TRANSCEIVER_RX:
+ /* Disable RX */
+ usart_hw->CTRLB.reg &= ~SERCOM_USART_CTRLB_RXEN;
+ module->receiver_enabled = false;
+ break;
+
+ case USART_TRANSCEIVER_TX:
+ /* Disable TX */
+ usart_hw->CTRLB.reg &= ~SERCOM_USART_CTRLB_TXEN;
+ module->transmitter_enabled = false;
+ break;
+ }
+}
+
+/** @} */
+
+#ifdef FEATURE_USART_LIN_MASTER
+/**
+ * \name LIN Master Command and Status
+ * @{
+ */
+
+/**
+ * \brief Sending LIN command.
+ *
+ * Sending LIN command.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] cmd Cammand type
+ */
+static inline void lin_master_send_cmd(
+ struct usart_module *const module,
+ enum lin_master_cmd cmd)
+{
+ SercomUsart *const usart_hw = &(module->hw->USART);
+ _usart_wait_for_sync(module);
+ usart_hw->CTRLB.reg |= cmd;
+}
+
+/**
+ * \brief Get LIN transmission status
+ *
+ * Get LIN transmission status.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ *
+ * \return Status of LIN master transmission.
+ * \retval true Data transmission completed
+ * \retval false Transmission is ongoing
+ */
+static inline bool lin_master_transmission_status(struct usart_module *const module)
+{
+ SercomUsart *const usart_hw = &(module->hw->USART);
+ return ((usart_hw->STATUS.reg & SERCOM_USART_STATUS_TXE)? true:false);
+}
+
+/** @} */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+/**
+* \page asfdoc_sam0_sercom_usart_extra Extra Information for SERCOM USART Driver
+*
+* \section asfdoc_sam0_sercom_usart_extra_acronyms Acronyms
+*
+* Below is a table listing the acronyms used in this module, along with their
+* intended meanings.
+*
+* <table>
+* <tr>
+* <th>Acronym</th>
+* <th>Description</th>
+* </tr>
+* <tr>
+* <td>SERCOM</td>
+* <td>Serial Communication Interface</td>
+* </tr>
+* <tr>
+* <td>USART</td>
+* <td>Universal Synchronous and Asynchronous Serial Receiver and Transmitter</td>
+* </tr>
+* <tr>
+* <td>LSB</td>
+* <td>Least Significant Bit</td>
+* </tr>
+* <tr>
+* <td>MSB</td>
+* <td>Most Significant Bit</td>
+* </tr>
+* <tr>
+* <td>DMA</td>
+* <td>Direct Memory Access</td>
+* </tr>
+* </table>
+*
+*
+* \section asfdoc_sam0_sercom_usart_extra_dependencies Dependencies
+* This driver has the following dependencies:
+*
+* - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver"
+* - \ref asfdoc_sam0_system_clock_group "System clock configuration"
+*
+*
+* \section asfdoc_sam0_sercom_usart_extra_errata Errata
+* There are no errata related to this driver.
+*
+*
+* \section asfdoc_sam0_sercom_usart_extra_history Module History
+* An overview of the module history is presented in the table below, with
+* details on the enhancements and fixes made to the module since its first
+* release. The current version of this corresponds to the newest version in
+* the table.
+*
+ * <table>
+ * <tr>
+ * <th>Changelog</th>
+ * </tr>
+ * <tr>
+ * <td>Added new feature as below:
+ * \li ISO7816
+ * </tr>
+ * <tr>
+ * <td>Added new features as below:
+ * \li LIN master
+ * \li RS485
+ * </tr>
+ * <tr>
+ * <td>Added new features as below:
+ * \li Oversample
+ * \li Buffer overflow notification
+ * \li Irda
+ * \li Lin slave
+ * \li Start frame detection
+ * \li Hardware flow control
+ * \li Collision detection
+ * \li DMA support </td>
+ * </tr>
+ * <tr>
+ * <td>\li Added new \c transmitter_enable and \c receiver_enable Boolean
+ * values to \c struct usart_config
+ * \li Altered \c usart_write_* and usart_read_* functions to abort with
+ * an error code if the relevant transceiver is not enabled
+ * \li Fixed \c usart_write_buffer_wait() and \c usart_read_buffer_wait()
+ * not aborting correctly when a timeout condition occurs</td>
+ * </tr>
+ * <tr>
+ * <td>Initial Release</td>
+ * </tr>
+ * </table>
+*/
+
+/**
+ * \page asfdoc_sam0_sercom_usart_exqsg Examples for SERCOM USART Driver
+ *
+ * This is a list of the available Quick Start guides (QSGs) and example
+ * applications for \ref asfdoc_sam0_sercom_usart_group. QSGs are simple examples with
+ * step-by-step instructions to configure and use this driver in a selection of
+ * use cases. Note that a QSG can be compiled as a standalone application or be
+ * added to the user application.
+ *
+ * - \subpage asfdoc_sam0_sercom_usart_basic_use_case
+ * \if USART_CALLBACK_MODE
+ * - \subpage asfdoc_sam0_sercom_usart_callback_use_case
+ * \endif
+ * - \subpage asfdoc_sam0_sercom_usart_dma_use_case
+ * - \subpage asfdoc_sam0_sercom_usart_lin_use_case
+ */
+
+/**
+ * \page asfdoc_sam0_sercom_usart_mux_settings SERCOM USART MUX Settings
+ *
+ * The following lists the possible internal SERCOM module pad function
+ * assignments, for the four SERCOM pads when in USART mode. Note that this is
+ * in addition to the physical GPIO pin MUX of the device, and can be used in
+ * conjunction to optimize the serial data pin-out.
+ *
+ * When TX and RX are connected to the same pin, the USART will operate in
+ * half-duplex mode if both one transmitter and several receivers are enabled.
+ *
+ * \note When RX and XCK are connected to the same pin, the receiver must not
+ * be enabled if the USART is configured to use an external clock.
+ *
+ *
+ * <table>
+ * <tr>
+ * <th>MUX/Pad</th>
+ * <th>PAD 0</th>
+ * <th>PAD 1</th>
+ * <th>PAD 2</th>
+ * <th>PAD 3</th>
+ * </tr>
+ * <tr>
+ * <td>RX_0_TX_0_XCK_1</td>
+ * <td>TX / RX</td>
+ * <td>XCK</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>RX_0_TX_2_XCK_3</td>
+ * <td>RX</td>
+ * <td>-</td>
+ * <td>TX</td>
+ * <td>XCK</td>
+ * </tr>
+ * <tr>
+ * <td>RX_1_TX_0_XCK_1</td>
+ * <td>TX</td>
+ * <td>RX / XCK</td>
+ * <td>-</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>RX_1_TX_2_XCK_3</td>
+ * <td>-</td>
+ * <td>RX</td>
+ * <td>TX</td>
+ * <td>XCK</td>
+ * </tr>
+ * <tr>
+ * <td>RX_2_TX_0_XCK_1</td>
+ * <td>TX</td>
+ * <td>XCK</td>
+ * <td>RX</td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>RX_2_TX_2_XCK_3</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>TX / RX</td>
+ * <td>XCK</td>
+ * </tr>
+ * <tr>
+ * <td>RX_3_TX_0_XCK_1</td>
+ * <td>TX</td>
+ * <td>XCK</td>
+ * <td>-</td>
+ * <td>RX</td>
+ * </tr>
+ * <tr>
+ * <td>RX_3_TX_2_XCK_3</td>
+ * <td>-</td>
+ * <td>-</td>
+ * <td>TX</td>
+ * <td>RX / XCK</td>
+ * </tr>
+ * </table>
+ *
+ * \page asfdoc_sam0_sercom_usart_document_revision_history Document Revision History
+ *
+ * <table>
+ * <tr>
+ * <th>Doc. Rev.</td>
+ * <th>Date</td>
+ * <th>Comments</td>
+ * </tr>
+ * <tr>
+ * <td>42118F</td>
+ * <td>12/2015</td>
+ * <td>Added support for SAM L21/L22, SAM DA1, SAM D09, SAMR30 and SAM C20/C21</td>
+ * </tr>
+ * <tr>
+ * <td>42118E</td>
+ * <td>12/2014</td>
+ * <td>Added support for SAM R21 and SAM D10/D11</td>
+ * </tr>
+ * <tr>
+ * <td>42118D</td>
+ * <td>01/2014</td>
+ * <td>Added support for SAM D21</td>
+ * </tr>
+ * <tr>
+ * <td>42118C</td>
+ * <td>10/2013</td>
+ * <td>Replaced the pad multiplexing documentation with a condensed table</td>
+ * </tr>
+ * <tr>
+ * <td>42118B</td>
+ * <td>06/2013</td>
+ * <td>Corrected documentation typos</td>
+ * </tr>
+ * <tr>
+ * <td>42118A</td>
+ * <td>06/2013</td>
+ * <td>Initial release</td>
+ * </tr>
+ * </table>
+ */
+#endif /* USART_H_INCLUDED */
diff --git a/atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.c b/atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.c
new file mode 100644
index 000000000..cc042894c
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.c
@@ -0,0 +1,666 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM USART Asynchronous Driver
+ *
+ * Copyright (C) 2012-2016 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+
+#include "usart_interrupt.h"
+
+/**
+ * \internal
+ * Asynchronous write of a buffer with a given length
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] tx_data Pointer to data to be transmitted
+ * \param[in] length Length of data buffer
+ *
+ */
+enum status_code _usart_write_buffer(
+ struct usart_module *const module,
+ uint8_t *tx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(tx_data);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ system_interrupt_enter_critical_section();
+
+ /* Check if the USART transmitter is busy */
+ if (module->remaining_tx_buffer_length > 0) {
+ system_interrupt_leave_critical_section();
+ return STATUS_BUSY;
+ }
+
+ /* Write parameters to the device instance */
+ module->remaining_tx_buffer_length = length;
+
+ system_interrupt_leave_critical_section();
+
+ module->tx_buffer_ptr = tx_data;
+ module->tx_status = STATUS_BUSY;
+
+ /* Enable the Data Register Empty Interrupt */
+ usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_DRE;
+
+ return STATUS_OK;
+}
+
+/**
+ * \internal
+ * Asynchronous read of a buffer with a given length
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] rx_data Pointer to data to be received
+ * \param[in] length Length of data buffer
+ *
+ */
+enum status_code _usart_read_buffer(
+ struct usart_module *const module,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+ Assert(rx_data);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ system_interrupt_enter_critical_section();
+
+ /* Check if the USART receiver is busy */
+ if (module->remaining_rx_buffer_length > 0) {
+ system_interrupt_leave_critical_section();
+ return STATUS_BUSY;
+ }
+
+ /* Set length for the buffer and the pointer, and let
+ * the interrupt handler do the rest */
+ module->remaining_rx_buffer_length = length;
+
+ system_interrupt_leave_critical_section();
+
+ module->rx_buffer_ptr = rx_data;
+ module->rx_status = STATUS_BUSY;
+
+ /* Enable the RX Complete Interrupt */
+ usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
+
+#ifdef FEATURE_USART_LIN_SLAVE
+ /* Enable the break character is received Interrupt */
+ if(module->lin_slave_enabled) {
+ usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXBRK;
+ }
+#endif
+
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ /* Enable a start condition is detected Interrupt */
+ if(module->start_frame_detection_enabled) {
+ usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXS;
+ }
+#endif
+
+ return STATUS_OK;
+}
+
+/**
+ * \brief Registers a callback
+ *
+ * Registers a callback function, which is implemented by the user.
+ *
+ * \note The callback must be enabled by \ref usart_enable_callback
+ * in order for the interrupt handler to call it when the conditions for
+ * the callback type are met.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] callback_func Pointer to callback function
+ * \param[in] callback_type Callback type given by an enum
+ *
+ */
+void usart_register_callback(
+ struct usart_module *const module,
+ usart_callback_t callback_func,
+ enum usart_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(callback_func);
+
+ /* Register callback function */
+ module->callback[callback_type] = callback_func;
+
+ /* Set the bit corresponding to the callback_type */
+ module->callback_reg_mask |= (1 << callback_type);
+}
+
+/**
+ * \brief Unregisters a callback
+ *
+ * Unregisters a callback function, which is implemented by the user.
+ *
+ * \param[in,out] module Pointer to USART software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ *
+ */
+void usart_unregister_callback(
+ struct usart_module *const module,
+ enum usart_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Unregister callback function */
+ module->callback[callback_type] = NULL;
+
+ /* Clear the bit corresponding to the callback_type */
+ module->callback_reg_mask &= ~(1 << callback_type);
+}
+
+/**
+ * \brief Asynchronous write a single char
+ *
+ * Sets up the driver to write the data given. If registered and enabled,
+ * a callback function will be called when the transmit is completed.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] tx_data Data to transfer
+ *
+ * \returns Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_BUSY If operation was not completed, due to the
+ * USART module being busy
+ * \retval STATUS_ERR_DENIED If the transmitter is not enabled
+ */
+enum status_code usart_write_job(
+ struct usart_module *const module,
+ const uint16_t *tx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(tx_data);
+
+
+ /* Check that the transmitter is enabled */
+ if (!(module->transmitter_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Call internal write buffer function with length 1 */
+ return _usart_write_buffer(module, (uint8_t *)tx_data, 1);
+}
+
+/**
+ * \brief Asynchronous read a single char
+ *
+ * Sets up the driver to read data from the USART module to the data
+ * pointer given. If registered and enabled, a callback will be called
+ * when the receiving is completed.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[out] rx_data Pointer to where received data should be put
+ *
+ * \returns Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_BUSY If operation was not completed
+ */
+enum status_code usart_read_job(
+ struct usart_module *const module,
+ uint16_t *const rx_data)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(rx_data);
+
+ /* Call internal read buffer function with length 1 */
+ return _usart_read_buffer(module, (uint8_t *)rx_data, 1);
+}
+
+/**
+ * \brief Asynchronous buffer write
+ *
+ * Sets up the driver to write a given buffer over the USART. If registered and
+ * enabled, a callback function will be called.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] tx_data Pointer do data buffer to transmit
+ * \param[in] length Length of the data to transmit
+ *
+ * \note If using 9-bit data, the array that *tx_data point to should be defined
+ * as uint16_t array and should be casted to uint8_t* pointer. Because it
+ * is an address pointer, the highest byte is not discarded. For example:
+ * \code
+ #define TX_LEN 3
+ uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133};
+ usart_write_buffer_job(&module, (uint8_t*)tx_buf, TX_LEN);
+ \endcode
+ *
+ * \returns Status of the operation.
+ * \retval STATUS_OK If operation was completed successfully.
+ * \retval STATUS_BUSY If operation was not completed, due to the
+ * USART module being busy
+ * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
+ * arguments
+ * \retval STATUS_ERR_DENIED If the transmitter is not enabled
+ */
+enum status_code usart_write_buffer_job(
+ struct usart_module *const module,
+ uint8_t *tx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(tx_data);
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ /* Check that the transmitter is enabled */
+ if (!(module->transmitter_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Issue internal asynchronous write */
+ return _usart_write_buffer(module, tx_data, length);
+}
+
+/**
+ * \brief Asynchronous buffer read
+ *
+ * Sets up the driver to read from the USART to a given buffer. If registered
+ * and enabled, a callback function will be called.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[out] rx_data Pointer to data buffer to receive
+ * \param[in] length Data buffer length
+ *
+ * \note If using 9-bit data, the array that *rx_data point to should be defined
+ * as uint16_t array and should be casted to uint8_t* pointer. Because it
+ * is an address pointer, the highest byte is not discarded. For example:
+ * \code
+ #define RX_LEN 3
+ uint16_t rx_buf[RX_LEN] = {0x0,};
+ usart_read_buffer_job(&module, (uint8_t*)rx_buf, RX_LEN);
+ \endcode
+ *
+ * \returns Status of the operation.
+ * \retval STATUS_OK If operation was completed
+ * \retval STATUS_BUSY If operation was not completed, due to the
+ * USART module being busy
+ * \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
+ * arguments
+ * \retval STATUS_ERR_DENIED If the transmitter is not enabled
+ */
+enum status_code usart_read_buffer_job(
+ struct usart_module *const module,
+ uint8_t *rx_data,
+ uint16_t length)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(rx_data);
+
+ if (length == 0) {
+ return STATUS_ERR_INVALID_ARG;
+ }
+
+ /* Check that the receiver is enabled */
+ if (!(module->receiver_enabled)) {
+ return STATUS_ERR_DENIED;
+ }
+
+ /* Issue internal asynchronous read */
+ return _usart_read_buffer(module, rx_data, length);
+}
+
+/**
+ * \brief Cancels ongoing read/write operation
+ *
+ * Cancels the ongoing read/write operation modifying parameters in the
+ * USART software struct.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] transceiver_type Transfer type to cancel
+ */
+void usart_abort_job(
+ struct usart_module *const module,
+ enum usart_transceiver_type transceiver_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+ Assert(module->hw);
+
+ /* Get a pointer to the hardware module instance */
+ SercomUsart *const usart_hw = &(module->hw->USART);
+
+ switch(transceiver_type) {
+ case USART_TRANSCEIVER_RX:
+ /* Clear the interrupt flag in order to prevent the receive
+ * complete callback to fire */
+ usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
+
+ /* Clear the software reception buffer */
+ module->remaining_rx_buffer_length = 0;
+
+ break;
+
+ case USART_TRANSCEIVER_TX:
+ /* Clear the interrupt flag in order to prevent the receive
+ * complete callback to fire */
+ usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;
+
+ /* Clear the software reception buffer */
+ module->remaining_tx_buffer_length = 0;
+
+ break;
+ }
+}
+
+/**
+ * \brief Get status from the ongoing or last asynchronous transfer operation
+ *
+ * Returns the error from a given ongoing or last asynchronous transfer operation.
+ * Either from a read or write transfer.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] transceiver_type Transfer type to check
+ *
+ * \return Status of the given job.
+ * \retval STATUS_OK No error occurred during the last transfer
+ * \retval STATUS_BUSY A transfer is ongoing
+ * \retval STATUS_ERR_BAD_DATA The last operation was aborted due to a
+ * parity error. The transfer could be affected
+ * by external noise
+ * \retval STATUS_ERR_BAD_FORMAT The last operation was aborted due to a
+ * frame error
+ * \retval STATUS_ERR_OVERFLOW The last operation was aborted due to a
+ * buffer overflow
+ * \retval STATUS_ERR_INVALID_ARG An invalid transceiver enum given
+ */
+enum status_code usart_get_job_status(
+ struct usart_module *const module,
+ enum usart_transceiver_type transceiver_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Variable for status code */
+ enum status_code status_code;
+
+ switch(transceiver_type) {
+ case USART_TRANSCEIVER_RX:
+ status_code = module->rx_status;
+ break;
+
+ case USART_TRANSCEIVER_TX:
+ status_code = module->tx_status;
+ break;
+
+ default:
+ status_code = STATUS_ERR_INVALID_ARG;
+ break;
+ }
+
+ return status_code;
+}
+
+/**
+ * \internal
+ * Handles interrupts as they occur, and it will run callback functions
+ * which are registered and enabled.
+ *
+ * \param[in] instance ID of the SERCOM instance calling the interrupt
+ * handler.
+ */
+void _usart_interrupt_handler(
+ uint8_t instance)
+{
+ /* Temporary variables */
+ uint16_t interrupt_status;
+ uint16_t callback_status;
+ uint8_t error_code;
+
+
+ /* Get device instance from the look-up table */
+ struct usart_module *module
+ = (struct usart_module *)_sercom_instances[instance];
+
+ /* Pointer to the hardware module instance */
+ SercomUsart *const usart_hw
+ = &(module->hw->USART);
+
+ /* Wait for the synchronization to complete */
+ _usart_wait_for_sync(module);
+
+ /* Read and mask interrupt flag register */
+ interrupt_status = usart_hw->INTFLAG.reg;
+ interrupt_status &= usart_hw->INTENSET.reg;
+ callback_status = module->callback_reg_mask &
+ module->callback_enable_mask;
+
+ /* Check if a DATA READY interrupt has occurred,
+ * and if there is more to transfer */
+ if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
+ if (module->remaining_tx_buffer_length) {
+ /* Write value will be at least 8-bits long */
+ uint16_t data_to_send = *(module->tx_buffer_ptr);
+ /* Increment 8-bit pointer */
+ (module->tx_buffer_ptr)++;
+
+ if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
+ data_to_send |= (*(module->tx_buffer_ptr) << 8);
+ /* Increment 8-bit pointer */
+ (module->tx_buffer_ptr)++;
+ }
+ /* Write the data to send */
+ usart_hw->DATA.reg = (data_to_send & SERCOM_USART_DATA_MASK);
+
+ if (--(module->remaining_tx_buffer_length) == 0) {
+ /* Disable the Data Register Empty Interrupt */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
+ /* Enable Transmission Complete interrupt */
+ usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
+
+ }
+ } else {
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
+ }
+ }
+
+ /* Check if the Transmission Complete interrupt has occurred and
+ * that the transmit buffer is empty */
+ if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {
+
+ /* Disable TX Complete Interrupt, and set STATUS_OK */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
+ module->tx_status = STATUS_OK;
+
+ /* Run callback if registered and enabled */
+ if (callback_status & (1 << USART_CALLBACK_BUFFER_TRANSMITTED)) {
+ (*(module->callback[USART_CALLBACK_BUFFER_TRANSMITTED]))(module);
+ }
+ }
+
+ /* Check if the Receive Complete interrupt has occurred, and that
+ * there's more data to receive */
+ if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
+
+ if (module->remaining_rx_buffer_length) {
+ /* Read out the status code and mask away all but the 4 LSBs*/
+ error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
+#if !SAMD20
+ /* CTS status should not be considered as an error */
+ if(error_code & SERCOM_USART_STATUS_CTS) {
+ error_code &= ~SERCOM_USART_STATUS_CTS;
+ }
+#endif
+#ifdef FEATURE_USART_LIN_MASTER
+ /* TXE status should not be considered as an error */
+ if(error_code & SERCOM_USART_STATUS_TXE) {
+ error_code &= ~SERCOM_USART_STATUS_TXE;
+ }
+#endif
+ /* Check if an error has occurred during the receiving */
+ if (error_code) {
+ /* Check which error occurred */
+ if (error_code & SERCOM_USART_STATUS_FERR) {
+ /* Store the error code and clear flag by writing 1 to it */
+ module->rx_status = STATUS_ERR_BAD_FORMAT;
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_FERR;
+ } else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
+ /* Store the error code and clear flag by writing 1 to it */
+ module->rx_status = STATUS_ERR_OVERFLOW;
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_BUFOVF;
+ } else if (error_code & SERCOM_USART_STATUS_PERR) {
+ /* Store the error code and clear flag by writing 1 to it */
+ module->rx_status = STATUS_ERR_BAD_DATA;
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_PERR;
+ }
+#ifdef FEATURE_USART_LIN_SLAVE
+ else if (error_code & SERCOM_USART_STATUS_ISF) {
+ /* Store the error code and clear flag by writing 1 to it */
+ module->rx_status = STATUS_ERR_PROTOCOL;
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_ISF;
+ }
+#endif
+#ifdef FEATURE_USART_COLLISION_DECTION
+ else if (error_code & SERCOM_USART_STATUS_COLL) {
+ /* Store the error code and clear flag by writing 1 to it */
+ module->rx_status = STATUS_ERR_PACKET_COLLISION;
+ usart_hw->STATUS.reg = SERCOM_USART_STATUS_COLL;
+ }
+#endif
+
+ /* Run callback if registered and enabled */
+ if (callback_status
+ & (1 << USART_CALLBACK_ERROR)) {
+ (*(module->callback[USART_CALLBACK_ERROR]))(module);
+ }
+
+ } else {
+
+ /* Read current packet from DATA register,
+ * increment buffer pointer and decrement buffer length */
+ uint16_t received_data = (usart_hw->DATA.reg & SERCOM_USART_DATA_MASK);
+
+ /* Read value will be at least 8-bits long */
+ *(module->rx_buffer_ptr) = received_data;
+ /* Increment 8-bit pointer */
+ module->rx_buffer_ptr += 1;
+
+ if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
+ /* 9-bit data, write next received byte to the buffer */
+ *(module->rx_buffer_ptr) = (received_data >> 8);
+ /* Increment 8-bit pointer */
+ module->rx_buffer_ptr += 1;
+ }
+
+ /* Check if the last character have been received */
+ if(--(module->remaining_rx_buffer_length) == 0) {
+ /* Disable RX Complete Interrupt,
+ * and set STATUS_OK */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
+ module->rx_status = STATUS_OK;
+
+ /* Run callback if registered and enabled */
+ if (callback_status
+ & (1 << USART_CALLBACK_BUFFER_RECEIVED)) {
+ (*(module->callback[USART_CALLBACK_BUFFER_RECEIVED]))(module);
+ }
+ }
+ }
+ } else {
+ /* This should not happen. Disable Receive Complete interrupt. */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
+ }
+ }
+
+#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
+ if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) {
+ /* Disable interrupts */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC;
+ /* Clear interrupt flag */
+ usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_CTSIC;
+
+ /* Run callback if registered and enabled */
+ if (callback_status & (1 << USART_CALLBACK_CTS_INPUT_CHANGE)) {
+ (*(module->callback[USART_CALLBACK_CTS_INPUT_CHANGE]))(module);
+ }
+ }
+#endif
+
+#ifdef FEATURE_USART_LIN_SLAVE
+ if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK) {
+ /* Disable interrupts */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXBRK;
+ /* Clear interrupt flag */
+ usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK;
+
+ /* Run callback if registered and enabled */
+ if (callback_status & (1 << USART_CALLBACK_BREAK_RECEIVED)) {
+ (*(module->callback[USART_CALLBACK_BREAK_RECEIVED]))(module);
+ }
+ }
+#endif
+
+#ifdef FEATURE_USART_START_FRAME_DECTION
+ if (interrupt_status & SERCOM_USART_INTFLAG_RXS) {
+ /* Disable interrupts */
+ usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS;
+ /* Clear interrupt flag */
+ usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS;
+
+ /* Run callback if registered and enabled */
+ if (callback_status & (1 << USART_CALLBACK_START_RECEIVED)) {
+ (*(module->callback[USART_CALLBACK_START_RECEIVED]))(module);
+ }
+ }
+#endif
+}
+
diff --git a/atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.h b/atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.h
new file mode 100644
index 000000000..26595d0a0
--- /dev/null
+++ b/atmel-samd/asf/sam0/drivers/sercom/usart/usart_interrupt.h
@@ -0,0 +1,177 @@
+/**
+ * \file
+ *
+ * \brief SAM SERCOM USART Asynchronous Driver
+ *
+ * Copyright (C) 2012-2015 Atmel Corporation. All rights reserved.
+ *
+ * \asf_license_start
+ *
+ * \page License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The name of Atmel may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * 4. This software may only be redistributed and used in connection with an
+ * Atmel microcontroller product.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * \asf_license_stop
+ *
+ */
+/*
+ * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
+ */
+#ifndef USART_INTERRUPT_H_INCLUDED
+#define USART_INTERRUPT_H_INCLUDED
+
+#include "usart.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(__DOXYGEN__)
+enum status_code _usart_write_buffer(
+ struct usart_module *const module,
+ uint8_t *tx_data,
+ uint16_t length);
+
+enum status_code _usart_read_buffer(
+ struct usart_module *const module,
+ uint8_t *rx_data,
+ uint16_t length);
+
+void _usart_interrupt_handler(
+ uint8_t instance);
+#endif
+
+/**
+ * \addtogroup asfdoc_sam0_sercom_usart_group
+ *
+ * @{
+ */
+
+/**
+ * \name Callback Management
+ * @{
+ */
+void usart_register_callback(
+ struct usart_module *const module,
+ usart_callback_t callback_func,
+ enum usart_callback callback_type);
+
+void usart_unregister_callback(
+ struct usart_module *module,
+ enum usart_callback callback_type);
+
+/**
+ * \brief Enables callback
+ *
+ * Enables the callback function registered by the \ref usart_register_callback.
+ * The callback function will be called from the interrupt handler when the
+ * conditions for the callback type are met.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+static inline void usart_enable_callback(
+ struct usart_module *const module,
+ enum usart_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Enable callback */
+ module->callback_enable_mask |= (1 << callback_type);
+
+}
+
+/**
+ * \brief Disable callback
+ *
+ * Disables the callback function registered by the \ref usart_register_callback,
+ * and the callback will not be called from the interrupt routine.
+ *
+ * \param[in] module Pointer to USART software instance struct
+ * \param[in] callback_type Callback type given by an enum
+ */
+static inline void usart_disable_callback(
+ struct usart_module *const module,
+ enum usart_callback callback_type)
+{
+ /* Sanity check arguments */
+ Assert(module);
+
+ /* Disable callback */
+ module->callback_enable_mask &= ~(1 << callback_type);
+}
+
+/**
+ * @}
+ */
+
+/**
+ * \name Writing and Reading
+ * @{
+ */
+enum status_code usart_write_job(
+ struct usart_module *const module,
+ const uint16_t *tx_data);
+
+enum status_code usart_read_job(
+ struct usart_module *const module,
+ uint16_t *const rx_data);
+
+enum status_code usart_write_buffer_job(
+ struct usart_module *const module,
+ uint8_t *tx_data,
+ uint16_t length);
+
+enum status_code usart_read_buffer_job(
+ struct usart_module *const module,
+ uint8_t *rx_data,
+ uint16_t length);
+
+void usart_abort_job(
+ struct usart_module *const module,
+ enum usart_transceiver_type transceiver_type);
+
+enum status_code usart_get_job_status(
+ struct usart_module *const module,
+ enum usart_transceiver_type transceiver_type);
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* USART_INTERRUPT_H_INCLUDED */
+
diff --git a/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c b/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c
index d2611b3d5..c5561b316 100644
--- a/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c
+++ b/atmel-samd/asf/sam0/utils/cmsis/samd21/source/gcc/startup_samd21.c
@@ -263,7 +263,7 @@ void Reset_Handler(void)
NVMCTRL->CTRLB.bit.MANW = 1;
/* Initialize the C library */
- __libc_init_array();
+ //__libc_init_array();
/* Branch to main function */
main();
diff --git a/atmel-samd/asf/sam0/utils/syscalls/gcc/syscalls.c b/atmel-samd/asf/sam0/utils/syscalls/gcc/syscalls.c
index c8c7ae605..45859e862 100644
--- a/atmel-samd/asf/sam0/utils/syscalls/gcc/syscalls.c
+++ b/atmel-samd/asf/sam0/utils/syscalls/gcc/syscalls.c
@@ -109,10 +109,10 @@ extern int _lseek(int file, int ptr, int dir)
return 0;
}
-extern void _exit(int status)
-{
- asm("BKPT #0");
-}
+// extern void _exit(int status)
+// {
+// asm("BKPT #0");
+// }
extern void _kill(int pid, int sig)
{