Lynx-EyEDの電音鍵盤 新館

制御とか数学とか駄文とか

第4世代の新オーディオDSP、SigmaDSP ADAU145xの試食

CES2014で発表されて以来ずっとウオッチしてきたADAU1452ですが、開発ツールSigmaStudioの対応が成熟してきたので使ってみようと思いました。主な特徴として

  • 最大294.912MHz動作
  • 周波数ドメインの演算ができるようになった(FFTなど)
  • Master Control Portを搭載しSPI/I2Cマスタとして動作するほか、外部のDAC/ADC/EEPROMなどのコンフィグができるようになった*1

ほかにも多くあるのですが、自分が注目したのはこのくらい。
ADAU170x/1401Aにあったヒルベルト変換が無いのですが、今後追加されるようです。
ところで、ADAU145xにはオーディオ用ADC/DACがありません。補助的な低精度のADCを持っているのみで、外付けする必要があります。それでも前述のようなことから採用する理由は十分にあると思います。(でも電池駆動のポータブルオーディオには向かないかも)

で、試食用ボード第1版。どーん。
f:id:Lynx-EyED:20150525214757j:plain
(実はDAC周りのピン設定がミスってて、SigmaDSPの設定を小細工しないと音が出ないなどの問題があり、修正版を実装依頼中の模様…)
主なデバイスはPIC32MX/SPI EEPROM/SigmaDSP/I2S DACといった構成。
PIC32MXがUSB-UART/USBスピーカーとして振る舞い、コンフィグデータのEEPROM書き込み、SigmaDSPへ音声データの送信を行います。

またDACとしてSSM2518を搭載しています。
しばらく遊べるおもちゃになりそうです。

*1:マイコンペリフェラルのような万能動作は期待できない。ブート前のワンショットシーケンサくらいに思ったほうがよいかも https://ez.analog.com/thread/43992

FlashAir単独でデータの符号化処理をする

FlashAirならではの使い方

仕事でFlashAirを冶具として使っているのですが、なかなか便利だったのでメモ。
5ピン分のGPIOが自由に使えるWi-Fi SDカード、というイメージが先行してしまいがちなのですが、速度がそこそこなので、このSDの旨みはそこじゃないんじゃないかなと。

  • 保存データの簡易的な暗号化

データをFlashAir内部に保存 → 保存時のトリガ*1Luaスクリプトを起動、データを算術・エントロピーの法則に基づいて符号化 → 元データ削除

データをFlashAir内部に保存 → 保存時のトリガでLuaスクリプトを起動、データを算術法則に基づいて符号化 → 圧縮

符号化処理

データの暗号化、圧縮ともに符号化が必要です。今回は符号化でよく使うであろう、ガンマ符号とデルタ符号用のスクリプトを書きました。

このブログを書いている2015年5月現在、FlashAirのLua機能には数学関数がないので、あまり複雑なことはできないかもしれませんが、少しの工夫で何とかなる場合も多いです。

今回用意した関数は

  • 引数の2進数表記での桁数を返す関数(function numOfDigits(num) )
  • ガンマ符号化を行い、値と桁数(2進数表記時)を返す関数(function gammaCoder(num))
  • デルタ符号化を行い、値と桁数(2進数表記時)を返す関数(function deltaCoder(num))

デルタ符号化はガンマ符号化関数を使い、符号化しています。
それぞれの符号の詳細は…
ガンマ符号 - Wikipedia
デルタ符号 - Wikipedia

コード

print("HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=utf-8\r\n")

local s_find   = string.find
local s_len    = string.len
local s_format = string.format
local fa_req   = fa.request
local i_close  = io.close
local i_open   = io.open
local L_shift  = bit32.lshift
local R_shift  = bit32.rshift
local b_and    = bit32.band
local b_or     = bit32.bor
local cjson    = require "cjson"

-----------------------------------------------
--	function: numOfDigits(num) 
--	digits(upto 32bits)
--	returns: Number of digits(Numbers when binary) 
-----------------------------------------------
function numOfDigits(num)
	local nod
	for kk = 1,32 do
		nod = kk
	 	num = R_shift(num,1)
	 	if num == 0 then 
	 		break
	 	end
	end
	return nod
end
-----------------------------------------------
--	function: gammaCoder(num) 
--	num: digits
--	returns: gamma code, number of gamma-coded-digits
-----------------------------------------------
function gammaCoder(num)
	local nndigits 
	nndigits = numOfDigits(num) * 2
	nndigits = nndigits - 1 		-- total number
	return num, nndigits
end
-----------------------------------------------
--	function: deltaCoder(num) 
--	num: digits
--	returns: gamma code, number of gamma-coded-digits
-----------------------------------------------
function deltaCoder(num)
	local nndigits,nndigitsX
	local numX
	nndigits = numOfDigits(num)
	numX, nndigitsX = gammaCoder(nndigits)
	nndigits = nndigits - 1
	
	numX = L_shift(numX, nndigits)
	
	num  = b_and(num, (2 ^ nndigits - 1)) 
	
	numX = b_or(num, numX)
	
	nndigits = nndigitsX + nndigits 		-- total number
	return numX, nndigits
end	

-- main program 


local c = 21 -- ここに符号化したい値を記述

local x,n = deltaCoder(c)
print(c.."のデルタ符号は"..x.."で、桁数は"..n.."<br><br>")
x,n = gammaCoder(c)
print(c.."のガンマ符号は"..x.."で、桁数は"..n.."<br><br>")

print("program end.")


-- main end

上記コードをUTF-8 BOM無しエンコードでFlashAirに保存してください。
ブラウザから動作確認すると、以下のようになると思います。

f:id:Lynx-EyED:20150513214132p:plain

おしまい。

*1:CONFIGにLUA_SD_EVENTを記述する。詳しくはhttps://flashair-developers.com/ja/documents/api/config/#LUA_SD_EVENT

FlashAirからTwitterに天気をポストする

前回のFlashAirネタの続きです

CJSONが使える

FlashAir W-03シリーズはLuaスクリプトが使えるわけですが、スクリプト中でCJSONも使えることが公式ページに書いてありました。へぇ、すごいじゃん。

JSON形式でデータが取り扱えると何かと便利です。
たとえばFlashAirならGPIO機能使って指定した時間にブザーを鳴らしたいとき
LuaでGPIO制御命令を記述し、時刻情報はJSON形式で
{”beep_date”:"20150510","beep_time":"06:30:00 JST"}
みたいなデータをupload.cgiでアップさせれば良いわけです。

天気情報の取得

今回は、CJSONのお勉強もかねて、天気予報をTwitterにポストさせてみました。使用した天気情報はOpenWeatherMap current weather and forecastのサービスです。

東京のお天気情報は
http://api.openweathermap.org/data/2.5/weather?q=Tokyo,jp
からJSON形式で取得できます。

データは以下のような構造になっています。

{
	"coord":{
		"lon":139.69,
		"lat":35.69
		},
	"sys":{
		"message":0.0325,
		"country":"JP",
		"sunrise":1431027729,
		"sunset":1431077599
	},
	"weather":[
		{
			"id":802,
			"main":"Clouds",
			"description":"scattered clouds",
			"icon":"03n"
		}
	],
	"base":"stations",
	"main":{
		"temp":288.78,
		"temp_min":288.78,
		"temp_max":288.78,
		"pressure":1021.85,
		"sea_level":1026.83,
		"grnd_level":1021.85,
		"humidity":99
	},
	"wind":{
		"speed":3.39,
		"deg":195.501
	},
	"clouds":{
		"all":44
	},
	"dt":1431092484,
	"id":1850147,
	"name":"Tokyo",
	"cod":200
}

Luaスクリプト

今回は

  • 天気情報(weather[0].description)
  • 最高気温(main.temp_max)
  • 最低気温(main.temp_min)

を取得してTwitterにポストしました。なお、Luaはデフォルトでは配列は[1]から始まるようなので天気情報はweather[1].descriptionとなります。なんだかMATLABみたい。

ポストには相変わらずStewgate-Uを使っています。

組み込み関数はローカルの参照を持ったほうが高速に動作するので、冒頭部分で宣言しています。

print("HTTP/1.1 200 OK\r\nContent-Type:text/html;charset=utf-8\r\n")

local s_find = string.find
local s_len = string.len
local fa_req = fa.request
local i_cloz = io.close
local i_open = io.open
local cjson = require "cjson"

contenttype = "application/json;charset=utf-8"			
bb,cc,hh = fa_req{url = "http://api.openweathermap.org/data/2.5/weather?q=Tokyo,jp",
		method = "GET", 
		headers = {["Content-Type"] = contenttype
			}
		}
bb = cjson.decode(bb)
print(bb.weather[1].description)

temp_min = tonumber(bb.main.temp_min) - 273.15 -- 絶対温度から摂氏に変換
temp_max = tonumber(bb.main.temp_max) - 273.15
weathe = bb.weather[1].description
			
bb,cc,hh = fa_req{url = "https://ntp-a1.nict.go.jp/cgi-bin/time",
			method = "GET"
		}

mes = "_t=(ここにStewgate-Uのトークンを書く)&msg=東京の最高気温: "..tostring(temp_max).."℃ 最低気温:"..tostring(temp_min).."℃ 天気: "..weathe..". posted at "..bb
blen = s_len(mes)
			
contenttype = "application/x-www-form-urlencoded"
b,c,h = fa_req{url = "http://stewgate-u.appspot.com/api/post/",
		 method = "POST",
		 headers = {["Content-Length"] = tostring(blen),
		 ["Content-Type"] = contenttype},
		body = mes
	}
print(tostring(b))

ブラウザから上記luaスクリプトを呼び出し、成功すると、
f:id:Lynx-EyED:20150508235102p:plain

なんか、最高気温=最低気温になっちゃってるね…。なんでだろ。

おしまい。

参考リンク

  • qiita.com
  • database-tearoom.seesaa.net



Microchip MPLABX/MPLAB harmonyでUSBオーディオデバイスを作る(前編)

必要に駆られ、PCからUSBオーディオデバイスとして見えるブツを作ることに。
数社のデバイスをピックアップし一通り試したのですが、PIC32を選定しました。
PICを選定した理由とか思った事とか、嵌まった所などメモ。
このブログの最後に今回作ったプロジェクトのgithubリンクを掲載しています。

MPLAB harmony

いつのまにかMicrochipからPIC32専用ファーム開発環境フレームワークが出ていました。
MPLAB Harmony | Home | Microchip Technology Inc.
MPLABXが採用しているNetbeansの機能に完全に支配されたフレームワークのようですが、使ってみた所感としてはMicrochip Libraries for Applications(MLA)のifdef地獄ライブラリから開放され、デバイススペシフィックにコードが生成できるため見通しは非常に良いです。

また生成されたアプリケーションはステートマシンが状態遷移をするコード構成になっておりRTOS移行時も比較的楽にできそうです。
またGPIOの入出力設定、初期状態のピンの論理もGUIで設定でき、かなり助かってます。(←ここ重要)

といいつつも今回のようにUSB周りを詳細にいじる場合はUSBデバイスディスクリプタなどスタック構造の知識を少し持っておかないといません。これは開発が容易といわれているCypress PSoC Creatorなどでも同様なので、設計自由度の高いUSBデバイスを作る開発環境では宿命なのかもしれません。しかしながらMPLAB harmonyもサンプルプロジェクトが豊富にあるのでそれを参考にできます。

PID/VIDでケチがつかないデバイスを作ることができる

MicrochipはNXPやFTDIなどと同様にUSBコントローラが自社デバイスであり、該当プロダクトの生産台数が10000台に達しないという条件の下、PIDをマイクロチップのVIDとともに使用する許可を申請できます(この情報について信頼を置ける権威ある文章は本家の英文です。必ず本家を参照のこと)https://www.microchip.com/usblicensing/Default.aspx
そのためオリジナルUSBデバイスで少量のデバイスしか作らない場合、PID/VIDにかかわる問題でケチがつかないデバイスを作ることができます。

使用したソフト/ハードなど

MPLAB harmonyはバージョンによってAPIが変わる可能性があります。このブログの内容を検証する際には以下の組み合わせを使用してください。

  • MPLABX IDE v.2.35
  • XC32-gcc compiler v.1.34(フリー版でOK)
  • MPLAB harmony v1_03_01

(インストール手順は割愛します。MPLAB harmonyはインストール後にMPLABXからロードできるようにする必要があります。この方法はMPLAB Harmonyのインストール完了後の画面で説明されます。)
使用したPICは秋月でお安いPIC32シリーズのPIC32MX220F032Bです。
PIC32MXは残念ながら正規の手法でUSBFS通信を行うには外部クロックが必要となります。16MHzのオシレータを接続しました。
また外付けオーディオDACを接続しようと思いますが、前編では、USBデバイスとして認識されるところまでの確認をしたいので、LEDを1つ、確認用に用意するだけにします。
参考回路図
f:id:Lynx-EyED:20150503234622p:plain

サンプルコードaudio_speakerを参考にUSBデバイスディスクリプタを修正

USBスピーカサンプルがharmonyに同梱されています。ターゲットデバイスがPIC32MZ2048なのでちょっと違うのですが参考になります。
参考にするのはsystem_init.cの"USB Stack Configuration"(123~470行目です)
このサンプルプロジェクトをPIC32MX220F032B用に書き換えていくという手もありかもしれませんが、構成が複雑なのでやめました。
まず新規にPIC32MX220F032B用にMPLABXプロジェクトをつくり、Tools->Embedded->MPLAB harmony Configurator を起動しMBLAB Harmony Configuratorタブで設定を行います。
変更するのは
USB Library
Device & Project Configuration
の二つです。
USB Libraryは下図の青でマーカーされている部分が変更点です
f:id:Lynx-EyED:20150503015037p:plain
Use USB Stack? -> check
Number of Endpoints Used: 2
USB Device Instance 0 -> check
Function 1 -> check
Number of Interfaces: 2
Device Class: AUDIO
Device & Project ConfigurationではPIC32MX220F032Bのクロックの設定がメインとなっています。ここが間違っているとどんなにがんばっても「USBデバイスが認識されません」とWindowsから言われてしまいます.
Device & Project Configuration ->
PIC32MX220F032B Device Configuration->
DEVCFG2->
FPLLDIV: DIV_4
FPLLMUL: MUL_20
UPLLDIV: DIV_4
UPLLEN: ON
FPLLODIV: DIV_1

DEVCFG1->
FNOSC: PRI
FSOSCEN: OFF
IESO: OFF
POSCMOD: HS
FPBDIV: DIV_1
FWDTEN: OFF

DEVCFG0
ICESEL: ICS_PGx2
PWP: 0xff

ポートの設定も行います。USBはポート固定されていますが、LEDを接続したRA0を出力に設定します。
MPLAB Harmony Pin Diagramタブを選択し、下部のMPLAB Pin Tableで、
Package: SPDIP
を選択し、Flagsをクリック。
f:id:Lynx-EyED:20150503232422p:plain
RA0の項目を
TRIS: OUT
LAT: Low
を選択しウィンドウを閉じる。
f:id:Lynx-EyED:20150503232449p:plain


ここまでできたら、Configurationボタンを押し、保存後Generateでコードを生成します。初回はOverwrite local changesにチェックをしても良いと思いますが、今後はsystem_init.cを手動で変更するので気をつけます。ここにチェックをしない場合、コードを変更してよいかGeneratorが聞いてきます。
生成後、先ほどのサンプルコードのsystem_init.cの"USB Stack Configuration"(123~470行目です)をコピーペーストしてしまいます。

メインとなるコードはapp.cです。ここにステートマシンが記述され、USBの状態により遷移するコードを記述します。
なお、audio_speakerのサンプルコードを元にapp.cを作りました。後述するgithubからダウンロードしてください。

今回LEDのみで実験する前提でした。なのでとりあえず動作(してるんだろうな?…って)確認ができる用のコードを記述します。
Windows上でオーディオスピーカをミュートする度にLEDがON->OFF->ONを繰り返すコードをapp.cに記述します。
f:id:Lynx-EyED:20150503230925p:plain
app.cの276行目付近の”case USB_DEVICE_AUDIO_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:”の部分を記述します。

case USB_DEVICE_AUDIO_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:
    USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK );
    if (appData.currentAudioControl == APP_USB_AUDIO_MUTE_CONTROL)
    {
        SYS_PORTS_PinToggle(PORTS_ID_0, PORT_CHANNEL_A, 0);  // <- これを追記
        appData.state = APP_MUTE_AUDIO_PLAYBACK;
        appData.currentAudioControl = APP_USB_CONTROL_NONE;
        //Handle Mute Control Here.
    }
    break;


コンパイル、書き込みを終え、PIC32MXをUSBで接続し、Harmony USB Speaker Exampleが認識できることを確認する。
f:id:Lynx-EyED:20150503233040p:plain

ミュートするたびにRA0に接続したLEDが点灯→消灯を繰り返すはずです。

今回作ったMPLABXプロジェクト

github.com

FlashAir W-03シリーズからTwitterにポストする

変態SDカード一族

GPIOがブラウザなどから自在に操れてしまう一部の頭がおかしい人たちに人気のFlashAirですが、
W-03(SD-WEシリーズ)からLuaスクリプトが動くので僕のような電子工作やネットワーク初心者でも格段に自由度の高いお遊びができます。わーい

https://flashair-developers.com/ja/documents/api/lua/

というわけで、さくっとTwitterにFlashAirのLuaスクリプトからポストしてみました。今回もStewgate-Uを使います。
TwitterにポストするのでFlashAirからも”外の世界”にアクセスできないといけません。FlashAirをインターネット同時接続モードにします。

不可視フォルダになってる/SD_WLAN/CONFIGを以下のように修正します。

APPMODE=6
APPNAME=myflashair
APPSSID=flashair
APPNETWORKKEY=
VERSION=FA9CAW3AW3.00.00
PRODUCT=FlashAir
VENDOR=TOSHIBA
LOCK=1
DNSMODE=0
BRGSSID=無線LANのSSID
BRGNETWORKKEY=無線LANのパスワード
APPAUTOTIME=0

保存します。

ルートディレクトリにLuaスクリプトを書きます。Twitterは同じメッセージを連投できないのでNICTからプレーンテキストでJST時刻を取得しメッセージの末尾にします。
Stewgate-Uについてはこちら

bb,cc,hh = fa.request{url = "https://ntp-a1.nict.go.jp/cgi-bin/time",
 method = "GET"
}
contenttype = "application/x-www-form-urlencoded"
msg = "うんこ"
mes = "_t=ここにStewgate-Uから発行されたトークンを書く&msg="..msg .. " posted at ".. tostring(bb)
blen = string.len(mes)
b,c,h = fa.request{url = "http://stewgate-u.appspot.com/api/post/",
 method = "POST",
 headers = {["Content-Length"] = tostring(blen),
 ["Content-Type"] = contenttype},
 body = mes
}
print(tostring(b))

これをscript.luaなどという名前でFlashAirのルートディレクトリに保存します。(UTF-8 BOM無しエンコードで保存)
FlashAirを一度アンマウントし、再マウントします。
しばらくすると”flashair”というSSIDが出現するのでPC等で接続しておきます。

ブラウザでhttp://myflashair/script.lua にアクセスすると…
f:id:Lynx-EyED:20150422204911p:plain

ミッション成功

おしまい。

Quartus II 14.0/14.1で初期値ありのUFMをインスタンシエートする

以前(アルテラCPLDで150LE未満のワンチップCPUを作ったお話 - Lynx-EyEDの電音鍵盤 新館)のときはQuartusII 13.1ベースで記事を書いていたので、14系列でかなりの変更があったと聞き、どう変わったか確認したときのメモです。

MegaWizardが消えたっぽい

MAX10 FPGAのUFMがAvalon-MMのモジュールとして使用できるようになっており(Altera On-Chip Flash)、その流れを受けてかMAX II/VのUFMもQsys経由でプロトコルや初期値のセットアップができるようになっています。
といってもMAXII/VのUFMはAvalon-MMのモジュールにならないので、後述するエクスポートするだけになります。

Qsysを今まで使っているなら特に問題ないと思いますが、Quartus IIでMAXII/Vのプロジェクトをつくり、Qsysを起動します(IP Catalogから起動してもOK)

UFMをSPIスレーブ、16bit,read onlyで初期化するので
画面左のIP Catalogからツリーをたどり、
Library -> Basic Functions -> On Chip Memory -> Altera USer Flash Memory for SPI Interface Protocol
を選択し、[add]ボタン
f:id:Lynx-EyED:20150103115111p:plain
プロトコルの詳細設定画面が出るので[General]タブで
Access mode : read only
Configuration mode : Extended mode (16bit address and data)
Port settings: Use 'osc' output port
にチェック
f:id:Lynx-EyED:20150103114123p:plain
次に[Initialization and Simulation]タブで
Memory Content Initialization: Initialize from hex or mif file
にチェックし、所望の初期値ファイル(ここではプロジェクトのルートにあらかじめ用意したUFM_Module.hex)を指定する。(後述:ここで問題が発生する)
して[Finish]する。
f:id:Lynx-EyED:20150103112801p:plain

QsysのSystem Contentsタブに戻り、
Avalonバス上につながるコネクションは今回ひとつもないので、すべてダブルクリックしてExportしておく。
f:id:Lynx-EyED:20150103112816p:plain
ここからはQsysのいつもの使い方なので駆け足で。
メニュー -> Generate -> Generate HDL -> Generate
Finish(Qsysを任意の名前で保存するのを忘れずに。)

Quartus II
Project -> Add/Remove Files in Project
で先ほどのQsysファイルをインポートする

インスタンシエート。自分はこんな感じでやりました

 qsys_ufm u0 (
	  .ufm_spi_0_ncs_ncs (ufm_ssel), // ufm_spi_0_ncs.ncs
	  .ufm_spi_0_osc_osc (int_osc), // ufm_spi_0_osc.osc
	  .ufm_spi_0_sck_sck (ufm_sclk), // ufm_spi_0_sck.sck
	  .ufm_spi_0_si_si   (ufm_mosi),   //  ufm_spi_0_si.si
	  .ufm_spi_0_so_so   (ufm_miso)    //  ufm_spi_0_so.so
 );

hexの中身が反映されない

これでコンパイルするとUFMに指定した初期値が反映されておりませんでした。
警告127003というのが目に付いたので見てみますと
f:id:Lynx-EyED:20150103112840p:plain

127003: Critical Warning (127003): Can't find Memory Initialization File or Hexadecimal (Intel-Format) File C:C:/altera/14.1/projects/ufm_module/altera14.1projectsufm_moduleUFM_Module.hex -- setting all initial values to 0

確かに初期値が読み込めてないっていうか、ファイル名バグってないですかこれ?System::Strings::Split('\')でも使って再連結するときに忘れたのかな(ぇ

対処:
プロジェクトフォルダからの相対パスでファイル名を指定する
自分の場合はプロジェクトのルートフォルダにUFM_Module.hexという名前で保存してあるので、
./UFM_Module.hex
f:id:Lynx-EyED:20150103113825p:plain
と記述し、先ほどと同じようにGenerate HDL -> Finish
コンパイルすれば、先ほどの警告はなくなり、初期値が反映される。

ちなみに

C:\altera\14.1\my_project_folder\my_project\my_ufm_data.hex という階層にhex/mifがある場合
C:\\altera\\14.1\\my_project_folder\\my_project\\my_ufm_data.hex
って書き直してやると動く模様。
でも、今後修正されたときにどんな挙動するかわかんなくなるし、やめたがいいかも。

JavaScriptでStewgate U経由でTwitterにポストする

半年近くブログ書いてない...

よく、OAuth非対応なArduinoやmbedや組み込みLinux機器から投稿する例は見るのですが、プレーンなhtml+JSでStewgate使うにはどうしたらいいのかなと悩んで、解決した後すぐ忘れてしまうのでメモ書き。

StewGate U: Throw your stuff into the stewittering pot.

ツイッタアカウントでログインすると、トークンというものがもらえます。

使い方
以下のURLにPOSTデータを送ると、StewGate UからTwitterアカウントに ポストできます:
        http://stewgate-u.appspot.com/api/post/

        POSTデータ:
        _t = (ここに取得したトークン)

        msg = "あなたの送信したいメッセージ"
        * UTF-8、URLエンコード済みにしてください。
        * メッセージに "%(name)s" を含めると、トークンの名前に置換されます。
        

        応答:
        OK (ポスト成功)
        エラーメッセージ (ポスト失敗)

と、あるので、(以下に続く)

XMLHttpRequestを使った例

というわけで、トークンをもらったら以下のコードを書きます。投稿後のレスポンスを取得したかったのでXMLHttpRequestを使いました。

var fd = new FormData(); 
	
fd.append("_t", "(取得したトークン)");
fd.append("msg","(ポストしたいメッセージ)");
	
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://stewgate-u.appspot.com/api/post/");

xhr.onload=function(){
	(レスポンスxhr.responseを表示するなりなんなり)
};
xhr.send(fd);

ちなみにTwitterは同じメッセージを連投できないので、メッセージに投稿時間や乱数を付け加えるのがいいと思います。

コピペ用全文

tweetした時間を投稿します。
スマートフォンなどからも使い易いようにスタイルシートを適用しています。

<html>
<head>
   <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
        <meta http-equiv="Content-type" content="text/html; charset=utf-8" target="_self">
            <style>
                .btn {
                    font-family: Arial, Helvetica, sans-serif;
                    font-size: 28px;
                    color: #fff;
                    padding: 12px 18px;
                    
                    background: #8893da;
                    background: -webkit-gradient(
                        linear, left top, left bottom,
                        from(#8893da),
                        to(#344c77)
                    );
                    
                    border-radius: 10px;
                    
                    -webkit-box-shadow:
                        12px 12px 12px rgba(000, 000, 000, 0.3),
                        inset 0px 0px 0px rgba(255, 255, 255, 0);
                    
                    text-shadow:
                    10px 10px 10px rgba(000, 000, 000, 1),
                    
                }
            </style>

<script type="text/javascript" charset="utf-8">

function postForm(){
	var fd = new FormData(); 
	
	var date_str = new Date();
	fd.append("_t", "(取得したトークン)");
	fd.append("msg","ただいまの時刻は"+date_str.getHours()+"時"+date_str.getMinutes() +"分"+date_str.getSeconds()+"秒です。");
	
	var xhr = new XMLHttpRequest();
	xhr.open("POST", "http://stewgate-u.appspot.com/api/post/");

	xhr.onload=function(){
		document.getElementById("stat").innerHTML = xhr.response; // レスポンスの表示
	};
	xhr.send(fd);
}

</script>
</head>
<body>
<div>
 <button class="btn" onclick="javascript:postForm()">POST_XHR</button>
</div>
<div id="stat"></div>
</body>
</html>

UTF-8エンコードで保存して、ブラウザから投稿テストします。POST_XHRのボタンを押すとTwitterにポストします。
うまくいけば、投稿ボタン真下にOKと出るはず。
f:id:Lynx-EyED:20141205221226p:plain
なにか時間経過で変化する事象をツイートする必要があれば、setInterval()などを使って上記関数を繰り返してもいいかもしれません。