component
STM32F103C8T6 - Arm Cortex-M3 MCU (Blue Pill)
Public Made by Adomby adom
STMicroelectronics mainstream Arm Cortex-M3 MCU. 72 MHz, 64 KB Flash, 20 KB SRAM, USB, CAN, LQFP-48. The workhorse Blue Pill microcontroller.
← Commit history
readme: packaged applets (pin-1 + datasheet-link), 225 inlined lines down to 16
2 files changed
+17−225
page.json+4−3@@ -4,7 +4,7 @@ "slug": "stm32f103c8t6", "title": "STM32F103C8T6 - Arm Cortex-M3 MCU (Blue Pill)", "brief": "STMicroelectronics mainstream Arm Cortex-M3 MCU. 72 MHz, 64 KB Flash, 20 KB SRAM, USB, CAN, LQFP-48. The workhorse Blue Pill microcontroller.",- "version": "0.2.4",+ "version": "0.2.5", "tags": [ "component", "microcontroller",@@ -160,9 +160,10 @@ "stm32f103c8t6-board.glb", "thumbnails/**" ],- "changelog": "0.2.4: symbol and footprint viewers above the README (sections array order, git-wiki #280).",+ "changelog": "0.2.5: applets are packaged now (one script tag), datasheet-link vote added, live price and stock from Component Ocean.", "applet_connect": [- "https://verify-3i7rt4do98l3.adom.cloud"+ "https://verify-3i7rt4do98l3.adom.cloud",+ "https://component-ocean-jk89eeqplwfl.adom.cloud" ], "sections": [ "hero",
readme.html+13−222@@ -136,228 +136,19 @@ tr[data-pin].hl td,tr[data-pin].hl td.data{color:var(--text)} </div> <h2 id=pin1>Which pad is pin 1 <span class=s>an applet: your confirmation goes to a real back-end, and the pad is verified once three independent reviewers agree</span></h2>-<style>-.p1wrap{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:16px;align-items:start;margin:10px 0 6px}-@media(max-width:760px){.p1wrap{grid-template-columns:1fr}}-.p1stage{background:var(--surface);border:1px solid var(--border);border-radius:12px;position:relative;- padding:14px;display:flex;align-items:center;justify-content:center;min-height:320px}-.p1stage svg{width:100%;max-width:420px;height:auto;display:block}-.p1badge{position:absolute;left:12px;top:10px;font:600 9.5px ui-monospace,monospace;letter-spacing:.12em;- text-transform:uppercase;color:var(--text-3);border:1px solid var(--border);border-radius:6px;padding:4px 8px}-.p1hint{position:absolute;right:12px;bottom:10px;font-size:10.5px;color:var(--text-3)}-.p1panel{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:16px;- display:flex;flex-direction:column;gap:12px}-.p1cons{background:var(--elevated);border:1px solid var(--border);border-radius:10px;padding:12px;- display:flex;flex-direction:column;gap:9px}-.p1lead{display:flex;justify-content:space-between;align-items:baseline}-.p1lk{font:600 9.5px ui-monospace,monospace;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3)}-.p1lv{font:600 14px ui-monospace,monospace;color:var(--text)}-.p1dots{display:flex;gap:6px}-.p1dot{height:7px;border-radius:4px;background:#243049;flex:1}-.p1dot.on{background:var(--accent-bright)}-.p1dot.ver{background:var(--green)}-.p1cs{font-size:12px;color:var(--text-2)}-.p1cs.ok{color:var(--green);font-weight:600}-.p1btn{background:var(--accent);color:#04110f;border:none;border-radius:9px;font:600 14px 'Satoshi',system-ui,sans-serif;- padding:11px;cursor:pointer}-.p1btn:disabled{opacity:.5;cursor:default}-.p1auth{font-size:11.5px;color:var(--text-3);font-family:ui-monospace,monospace;display:flex;gap:6px;align-items:center;flex-wrap:wrap}-.p1auth b{color:var(--text-2)}-.p1auth a{color:var(--accent-bright);cursor:pointer}-.p1in{flex:1;min-width:110px;background:var(--elevated);border:1px solid var(--border);border-radius:8px;color:var(--text);- font:500 12.5px 'Satoshi',system-ui,sans-serif;padding:8px 10px;outline:none}-.p1in:focus{border-color:var(--accent)}-.p1reason{display:none;flex-direction:column;gap:6px}-.p1reason.show{display:flex}-.p1rl{font:600 9.5px ui-monospace,monospace;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3)}-.p1rl i{color:var(--accent-bright);font-style:normal}-.p1notes{display:flex;flex-direction:column;gap:6px}-.p1nh{font:600 9.5px ui-monospace,monospace;letter-spacing:.08em;text-transform:uppercase;color:var(--text-3)}-.p1row{display:flex;gap:7px;align-items:baseline;font-size:12px;line-height:1.4}-.p1row .nv{font:600 10.5px ui-monospace,monospace;color:var(--text-3);white-space:nowrap}-.p1row .npad{font:600 10.5px ui-monospace,monospace;color:var(--accent-bright);white-space:nowrap}-.p1row .ntxt{color:var(--text-2)}-.p1row .none{color:var(--text-3);font-style:italic}-.p1row.you .nv{color:var(--accent-bright)}-.p1row.src .nv{color:var(--blue)}-.p1row.src .ntxt{color:var(--text-3)}-.p1foot{font-size:11px;color:var(--text-3);line-height:1.5}-.p1foot code{color:var(--accent-bright);font-family:ui-monospace,monospace}-.p1pad{fill:#59657e;stroke:#8b98af;stroke-width:.6;cursor:pointer}-.p1pad:hover{fill:#7d8aa3}-.p1pad.ver{fill:var(--green);stroke:#04110f}-.p1pad.sel{fill:var(--accent-bright);stroke:#04110f}-.p1num{fill:#8592a8;font:600 8.5px ui-monospace,monospace;pointer-events:none;dominant-baseline:middle}-.p1body{fill:#141a22;stroke:#2f3d57;stroke-width:1.5}-.p1dimple{fill:#0d1117;stroke:#8b98af;stroke-width:1}-</style>-<div class=p1wrap>- <div class=p1stage>- <svg id=p1fp viewBox="0 0 560 560" xmlns="http://www.w3.org/2000/svg"></svg>- <div class=p1badge id=p1badge>confirm or claim pin 1</div>- <div class=p1hint>manufacturer pin-1 dimple = top-left</div>- </div>- <div class=p1panel>- <div class=p1cons>- <div class=p1lead><span class=p1lk>current pin 1</span><span class=p1lv id=p1lead>—</span></div>- <div class=p1dots id=p1dots><div class=p1dot></div><div class=p1dot></div><div class=p1dot></div></div>- <div class=p1cs id=p1cs>checking the service…</div>- </div>- <div class=p1reason id=p1reasonwrap>- <div class=p1rl>Why is this pad pin 1? <i>· required</i></div>- <input class=p1in id=p1reason type=text maxlength=120 spellcheck=false placeholder="e.g. dimple + bevel are on this corner">- </div>- <button class=p1btn id=p1pick disabled>Confirm pin 1</button>- <div class=p1auth id=p1auth></div>- <div class=p1notes id=p1notes></div>- <p class=p1foot>The button calls <code>adom-verify</code>, this page's declared back-end. A vote is tied to a- signed-in account, so three independent reviewers means three people.</p>- </div>-</div>-<script>-(function(){- var MPN='STM32F103C8T6', FACT='pin-1';- // The starting pin 1 is real provenance, not a seeded vote: the KiCad footprint- // on this page declares it. Human confirmations start at zero.- var AUTO_PIN='1', AUTO_SOURCE='footprint', AUTO_BASIS='declared as pin 1 in the KiCad footprint';- var SVC='https://verify-3i7rt4do98l3.adom.cloud/'; // page.json applet_connect declares this origin- var $=function(id){return document.getElementById(id);};- // localStorage throws in the readme sandbox (opaque origin), so keep the session in memory there- var store=(function(){try{localStorage.setItem('_p1','1');localStorage.removeItem('_p1');return localStorage;}- catch(e){var m={};return{getItem:function(k){return m[k]||null;},setItem:function(k,v){m[k]=v;},removeItem:function(k){delete m[k];}};}})();- var TOKEN=store.getItem('verifyToken')||'', ME=null, selected=null, currentPin1=AUTO_PIN, signingIn=false;- function esc(s){return String(s).replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c];});}- function hdrs(){return TOKEN?{'Authorization':'Bearer '+TOKEN}:{};}-- // ---- LQFP-48 top view: 12 pads a side, pin 1 top-left, counter-clockwise ----- var NS='http://www.w3.org/2000/svg', N=12, BODY=310, PADL=36, PADW=11, GAP=BODY/N, bl=280-BODY/2;- var svg=$('p1fp');- function el(t,a){var e=document.createElementNS(NS,t);for(var k in a)e.setAttribute(k,a[k]);svg.appendChild(e);return e;}- el('rect',{x:bl,y:bl,width:BODY,height:BODY,rx:10,'class':'p1body'});- el('circle',{cx:bl+22,cy:bl+22,r:9,'class':'p1dimple'});- function pad(x,y,w,h,n){var r=el('rect',{x:x,y:y,width:w,height:h,rx:2.5,'class':'p1pad'});r.setAttribute('data-pin',n);return r;}- function num(x,y,anchor,n){var t=el('text',{x:x,y:y,'text-anchor':anchor,'class':'p1num'});t.textContent=n;}- var pin=1,i,yc,xc;- for(i=0;i<N;i++){yc=bl+GAP/2+i*GAP;pad(bl-PADL,yc-PADW/2,PADL,PADW,pin);num(bl-PADL-7,yc,'end',pin);pin++;}- for(i=0;i<N;i++){xc=bl+GAP/2+i*GAP;pad(xc-PADW/2,bl+BODY,PADW,PADL,pin);num(xc,bl+BODY+PADL+13,'middle',pin);pin++;}- for(i=0;i<N;i++){yc=bl+BODY-GAP/2-i*GAP;pad(bl+BODY,yc-PADW/2,PADL,PADW,pin);num(bl+BODY+PADL+7,yc,'start',pin);pin++;}- for(i=0;i<N;i++){xc=bl+BODY-GAP/2-i*GAP;pad(xc-PADW/2,bl-PADL,PADW,PADL,pin);num(xc,bl-PADL-8,'middle',pin);pin++;}-- function targetPin(){return selected||currentPin1;}- function confirming(){var t=targetPin();return t&&t===currentPin1;}- function updateBtn(){- var b=$('p1pick'), t=targetPin();- if(!ME){$('p1reasonwrap').classList.remove('show');b.disabled=false;b.textContent='Sign in to vote';return;}- if(!t){b.disabled=true;b.textContent='Pick a pad';return;}- if(confirming()){$('p1reasonwrap').classList.remove('show');b.disabled=false;b.textContent='Confirm pad '+t+' is pin 1';return;}- $('p1reasonwrap').classList.add('show');- if(!$('p1reason').value.trim()){b.disabled=true;b.textContent='Add a reason to claim pad '+t;return;}- b.disabled=false;b.textContent='Claim pad '+t+' is pin 1';- }- svg.addEventListener('click',function(e){- var p=e.target.closest('.p1pad');if(!p)return;- [].forEach.call(svg.querySelectorAll('.p1pad.sel'),function(x){x.classList.remove('sel');});- selected=p.getAttribute('data-pin');- if(selected!==currentPin1)p.classList.add('sel'); // teal marks a claim on a different pad- updateBtn();- if($('p1reasonwrap').classList.contains('show'))$('p1reason').focus();- });- $('p1reason').addEventListener('input',updateBtn);-- // ---- identity (no prompt(): modals are blocked in the readme sandbox) ----- function renderAuth(msg){- var el=$('p1auth');- if(ME){el.innerHTML='signed in as <b>'+esc(ME.name)+'</b> · <a id=p1out>sign out</a>';- $('p1out').onclick=function(){TOKEN='';store.removeItem('verifyToken');ME=null;renderAuth();updateBtn();};return;}- if(signingIn){el.innerHTML='<input class=p1in id=p1handle placeholder="your name or handle" maxlength=40>'- +'<a id=p1go>sign in</a> <a id=p1cancel style="color:var(--text-3)">cancel</a>';- var h=$('p1handle');h.focus();- h.onkeydown=function(e){if(e.key==='Enter')doSignIn();};- $('p1go').onclick=doSignIn;- $('p1cancel').onclick=function(){signingIn=false;renderAuth();};return;}- // signed out: the button already says "Sign in to vote", so this line explains why- el.innerHTML=msg?'<span style="color:var(--red)">'+esc(msg)+'</span>':'a vote is tied to your account, not this browser';- }- function doSignIn(){- var handle=($('p1handle')&&$('p1handle').value||'').trim();- if(!handle)return;- fetch(SVC+'auth/dev',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({handle:handle})})- .then(function(r){return r.json();})- .then(function(j){- if(!j.token)throw new Error(j.error||'sign-in failed');- TOKEN=j.token;store.setItem('verifyToken',TOKEN);signingIn=false;- return loadMe().then(function(){renderAuth();updateBtn();load();});- })- .catch(function(e){signingIn=false;renderAuth(e.message);});- }- function loadMe(){- if(!TOKEN){ME=null;return Promise.resolve();}- return fetch(SVC+'me',{headers:hdrs()}).then(function(r){return r.json();})- .then(function(j){ME=j.authed?j:null;}).catch(function(){ME=null;});- }-- // ---- consensus ----- function renderNotes(picks){- var src='<div class="p1row src"><span class=nv>'+esc(AUTO_SOURCE)+'</span><span class=npad>pad '+esc(AUTO_PIN)- +'</span><span class=ntxt>'+esc(AUTO_BASIS)+'</span></div>';- var human='';- if(picks&&picks.length){- human=picks.slice().sort(function(a,b){return (a.value-b.value)||String(a.name).localeCompare(String(b.name));})- .map(function(p){- var you=ME&&p.voter===ME.voter;- var txt=p.reason?('“'+esc(p.reason)+'”'):'<span class=none>no reason given</span>';- return '<div class="p1row'+(you?' you':'')+'"><span class=nv>'+esc(you?'you':p.name)+'</span>'- +'<span class=npad>pad '+esc(p.value)+'</span><span class=ntxt>'+txt+'</span></div>';- }).join('');- }- $('p1notes').innerHTML='<div class=p1nh>provenance & reviewer picks</div>'+src+human;- }- function render(s){- currentPin1=s.verified_value||s.leader||AUTO_PIN;- var c=(s.tally&&s.tally[currentPin1])||0;- $('p1lead').textContent='pad '+currentPin1;- var dots=$('p1dots').children;- for(var i=0;i<3;i++)dots[i].className='p1dot'+(i<c?(s.verified?' ver':' on'):'');- [].forEach.call(svg.querySelectorAll('.p1pad.ver'),function(x){x.classList.remove('ver');});- var vp=svg.querySelector('.p1pad[data-pin="'+currentPin1+'"]');if(vp)vp.classList.add('ver');- if(s.verified){- $('p1cs').textContent='verified ✓ pin 1 = pad '+s.verified_value+' ('+c+'/'+s.needed+' agree)';- $('p1cs').classList.add('ok');$('p1badge').textContent='pin 1 verified';- }else{- $('p1cs').classList.remove('ok');$('p1badge').textContent='confirm or claim pin 1';- $('p1cs').textContent=c>0- ? 'pad '+currentPin1+' · '+c+' of '+s.needed+' reviewer confirmations · '+(s.needed-c)+' more needed'- : 'from the '+AUTO_SOURCE+' · 0 of '+s.needed+' reviewer confirmations';- }- renderNotes(s.picks);updateBtn();- }- function load(){- return fetch(SVC+'status?page='+encodeURIComponent(MPN)+'&fact='+FACT)- .then(function(r){return r.json();}).then(render)- .catch(function(){$('p1cs').textContent='verification service unreachable';});- }- $('p1pick').addEventListener('click',function(){- if(!ME){signingIn=true;renderAuth();return;}- var t=targetPin();if(!t)return;- var conf=confirming(), note=$('p1reason').value.trim();- if(!conf&&!note)return;- $('p1pick').disabled=true;$('p1pick').textContent='Submitting…';- fetch(SVC+'vote?page='+encodeURIComponent(MPN)+'&fact='+FACT+'&value='+t+'&reason='+encodeURIComponent(conf?'':note),- {method:'POST',headers:hdrs()})- .then(function(r){- if(r.status===401){TOKEN='';store.removeItem('verifyToken');ME=null;renderAuth('session expired');updateBtn();return null;}- return r.json();})- .then(function(s){- if(!s)return;- selected=null;$('p1reason').value='';- [].forEach.call(svg.querySelectorAll('.p1pad.sel'),function(x){x.classList.remove('sel');});- render(s);})- .catch(function(e){$('p1cs').textContent='vote failed: '+e.message;updateBtn();});- });- svg.querySelector('.p1pad[data-pin="'+AUTO_PIN+'"]').classList.add('ver');- loadMe().then(function(){renderAuth();updateBtn();return load();});-})();-</script>+<script src="https://verify-3i7rt4do98l3.adom.cloud/applet.js"></script>+<adom-verify+ page="STM32F103C8T6" fact="pin-1"+ pins="48" package="LQFP-48"+ source="footprint" source-value="1"+ source-basis="declared as pin 1 in the KiCad footprint"></adom-verify>++<h2 id=datasheet-vote>Is this the right datasheet <span class=s>the same back-end, a different fact: confirm the manufacturer document for this exact part, or propose a better one</span></h2>+<adom-verify+ page="STM32F103C8T6" fact="datasheet-link"+ source="page" source-value="https://www.st.com/resource/en/datasheet/stm32f103cb.pdf"+ source-basis="the datasheet declared in page.json"+ values='["https://www.st.com/resource/en/datasheet/stm32f103cb.pdf","https://www.st.com/resource/en/reference_manual/rm0008-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf"]'></adom-verify> <h2>Datasheet key pages <span class=s>the pages worth looking at first · pick a page, click it to go full screen</span></h2> <div class=dsviewer>