module App.WS1228B
where
import STM32.API as API
import STM32.GPIO as GPIO
import STM32.SPI as SPI
import STM32.DMA as DMA
import qualified Data.ByteString as BS
import Control.Monad
data RGB = RGB Word8 Word8 Word8
deriving (Read,Show,Eq,Ord)
testLEDs :: IO ()
testLEDs = sendLEDs [red,green,blue,black,white]
ledsOff30 :: IO ()
ledsOff30 = sendLEDs $ replicate 30 black
sendLEDs :: [RGB] -> IO ()
sendLEDs colors = runMI $ do
initSPI
sendSPI $ encodeRGBLine colors
black :: RGB
black = RGB 0x00 0x00 0x00
white :: RGB
white = RGB 0xff 0xff 0xff
red :: RGB
red = RGB 0xff 0x00 0x00
green :: RGB
green = RGB 0x00 0xff 0x00
blue :: RGB
blue = RGB 0x00 0x00 0xff
encodeRGBLine :: [RGB] -> BS.ByteString
encodeRGBLine l = BS.concat (resetCode : map encodeRGB l)
resetCode :: BS.ByteString
resetCode = BS.pack $ replicate 20 0x00
encodeRGB :: RGB -> BS.ByteString
encodeRGB (RGB r g b)
= BS.pack [g3,g2,g1,r3,r2,r1,b3,b2,b1]
where
(r3,r2,r1) = lineCodeWord8 r
(g3,g2,g1) = lineCodeWord8 g
(b3,b2,b1) = lineCodeWord8 b
lineCodeWord8 :: Word8 -> (Word8,Word8,Word8)
lineCodeWord8 b = (c1,c2,c3)
where
c1 = fromIntegral ((mix32 `shiftR` 16) .&. 0xff)
c2 = fromIntegral ((mix32 `shiftR` 8) .&. 0xff)
c3 = fromIntegral (mix32 .&. 0xff)
mix32 :: Word32
mix32 = worker 7 0
worker (1) accum = accum
worker n accum = worker (n 1) ((accum `shiftL` 3) .|. bitCode)
where bitCode = if b `testBit` n then 6 else 4
led :: Wire
led = (GPIOA,Pin_12)
spi_mosi :: Wire
spi_mosi=(GPIOB,Pin_15)
spiConfig :: SPI.Config
spiConfig = SPI.Config {
_direction = One_Line_Tx
, _mode = Master
, _dataSize = Eight
, _CPOL = SPI.Low
, _CPHA = OneEdge
, _NSS = Soft
, _baudRatePrescaler = Prescaler_16
, _firstBit = MSB
, _CRCPolynomial = 7
}
initSPI :: MI ()
initSPI = do
initMI
API.resetHalt
setDefaultClocks
SPI.deInit SPI2
peripheralClockOn GPIOB
peripheralClockOn GPIOC
peripheralClockOn SPI2
pinMode led $ GPOutPushPull MHz_2
pinMode spi_mosi $ GPIO.AlternateOutPushPull MHz_2
SPI.init SPI2 spiConfig
bitSet SPI2 CR2_TXDMAEN
SPI.enable SPI2
sendSPI :: BS.ByteString -> MI ()
sendSPI bs = do
let len = BS.length bs
dmaBuffer = 0x20001000
dmaConfig = DMA.Config {
_BufferSize = fromIntegral $ len
,_Direction = PeripheralDST
,_MemoryBaseAddr = dmaBuffer
,_MemoryDataSize = Byte
,_MemoryInc = True
,DMA._Mode = Normal
,_PeripheralBaseAddr = regToAddr SPI2 DR
,_PeripheralDataSize = Byte
,_PeripheralInc = False
,_Priority = DMA.High
}
writeMem8 dmaBuffer bs
peripheralClockOn DMA1
DMA.deInit DMA1_Channel5
DMA.disable DMA1_Channel5
DMA.init DMA1_Channel5 dmaConfig
DMA.enable DMA1_Channel5
return ()
testWave :: IO ()
testWave = runMI $ do
initSPI
let
st = 2*pi/10
loop t = do
let colors = [RGB (redIntensity $ wave t st i)
(redIntensity $ wave (t*0.5) st i) 0
| i <- [0..15]]
sendSPI $ encodeRGBLine colors
delay 1000
loop $ t + 0.1
loop 0
wave :: Double -> Double -> Int -> Double
wave t st i = (sin (t+st* fromIntegral i) +1) /2
redIntensity :: Double -> Word8
redIntensity d =
if d >0.4 then floor (d*5)
else 0