Uncategorized

SPI 1 Study notes

0
2

Raspberry pi newbie here. As part of my academics i was working on Raspberry Pi 3 B+ , Raspbian OS kernel 4.14.98-v7 and i was testing protocols and i am stuck at SPI.

I am running spidev_test.c from https://github.com/torvalds/linux/blob/master/tools/spi/spidev_test.c to test my SPI. Pin connections i have done

(Pin 21) MISO – MOSI (Pin 19)

(Pin 19) MOSI – MISO (Pin 21)

(Pin 23) SCLK – Logic Analyzer 0

(Pin 11) CS – Logic Analyzer 1

I am using spidev0.1 in the program as device.

I was observing the outputs in my logic analyzer i got from the department lab and i noticed as i increase the frequency in the code spidev_test.c static uint32_t speed = 500000;

The logic voltage level of my SCLK keeps decreasing. The CS output is proper 3.3 for high and 0 for low.

Upto 800 Khz i get somewhere around 3.29 and after that it starts to reduce. I want to test my SPI on 9.6Mhz for which i am getting a voltage around 1.6 V.

I double checked if SPI is enabled or not and it is enabled. I am not able to debug the Error. Any feedback would be helpful.

EDIT 1: Screenshot at 5Mhz enter image description here

Channel 2 is SCLK Channel 3 is CS

 New contributor

1

Question

SPI 800kHz CLK amplitude is 3.29V, and decreases as SPI frequency increases,
SPI 9.6 MHz amplitude is only 1.6V, …

Answer

For my Rpi3B+ stretch9, SPI 100kHz, 1MHz, and 5MHz, signal amplitude does not change noticeably, …

References

Rpi SPI Pinout

SPI1 (Auxiliary SPI) Config and Kernel Module

Appendices

Appendix A – SPI Signal Waveforms at 5MHz

spi 5mhz

Appendix B – SPI Test Program

# Program  - spi_test_v1312_2019jul0301 tlfong01 2019jul03hkt1027 
# Config   - Rpi3B+ raspberrypi 4.19.42-v7+, IDLE python 3.5.3
# Function - (1) SPI loopback 1/2/3 bytes, (2) SPI repeat send one byte

# Rpi Interfaces Configuration dtparam= 
# SPI, I2C, 1-Wire enable, Serial Port diaable

# Test 1    - loopBackTest - SPI port send and receive 1/2/3 bytes.
# Function - Send 1/2/3 bytes to MOSI and read it back from MISO. 
# Setup    - Connet MOSI pin to MISO pin to form a loop.

# Test 2   - repeat send one byte - SPI port repeat send one byte (need a scope to display waveforms).
# Function - repeat send data byte 0x5b and use scope to display waveforme CLK. MOSI, MISO, CS0, CS1. 
# Setup    - nil

# dtoverlay to enable SPI Channal 1 and Channal 1
# /boot/config.txt dtoverlay setting 
# dtparam=i2c_arm=on
# dtparam=spi=on
# dtoverlay=spi1-3cs

# /dev/spi listing
# ls -l /dev/spi*
# should show the following:
# 1. /dev/spidev0.0
# 2. /dev/spidev0.1
# 3. /dev/spidev1.0
# 4. /dev/spidev1.1
# 5. /dev/spidev1.2

from   time import sleep
import spidev

# *** SPI Setup/Config ***

spiPort00 = spidev.SpiDev()
spiPort00.open(0, 0)
# spiPort00.max_speed_hz   =  100000  # 0.1 MHz (100 kHz)
# spiPort00.max_speed_hz   = 1000000  #   1 MHz
spiPort00.max_speed_hz     = 5000000  #   5 MHz 

spiPort01 = spidev.SpiDev()
spiPort01.open(0, 1)
spiPort01.max_speed_hz = 100000

# *** Not tested - tlfong01  2019jul03hkt1047 ***

'''
spiPort10 = spidev.SpiDev()
spiPort10.open(1, 0)
spiPort10.max_speed_hz = 100000

spiPort11 = spidev.SpiDev()
spiPort11.open(1, 1)
spiPort11.max_speed_hz = 100000

spiPort12 = spidev.SpiDev()
spiPort12.open(1, 2)
spiPort12.max_speed_hz = 100000
'''

# *** Spi port functions ***

def setSpiPortSpeed(spiPortNum, speedName):
    spiPortList[spiPortNum].max_speed_hz = speedDict[speedName]
    return

def closeSpiPortAll():
    for i in spiPortList:
        i.close()
    return

def padDataByte(dataByte):
    unPadString = (hex(dataByte)[2:])
    if (len(unPadString) != 2):
        unPadString = '0' + unPadString
    padString = '0x' + unPadString
    return padString

def printTitleDataByte(title, dataByte):
    print(title, padDataByte(dataByte))
    return

# *** SPI Write/Read/Loopback 1/2/3 Bytes ***

# *** SPI Send/Receive 1/2/3 Bytes ***

def spiSendRecvOneByte(spiPort, sendByte):
    sendByteArray = [sendByte]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

def spiSendRecvTwoBytes(spiPort, sendByte1, sendByte2):
    sendByteArray = [sendByte1, sendByte2]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

def spiSendRecvThreeBytes(spiPort, sendByte1, sendByte2, sendByte3):
    sendByteArray = [sendByte1, sendByte2, sendByte3]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

# *** Loopback 1/2/3 Bytes ***

def loopbackOneByte(spiPort, sendByte):
    recvByteArray     = spiSendRecvOneByte(spiPort, sendByte)
    recvByte          = recvByteArray[0]
    print('\n  Begin loopbackOneByte(),...')
    printTitleDataByte('      sendByte  = ', sendByte)
    printTitleDataByte('      recvByte  = ', recvByte)
    #print('')
    print('  End   loopbackOneByte().', end = '')
    return

def loopbackTwoBytes(spiPort, sendByte1, sendByte2):
    recvByteArray     = spiSendRecvTwoBytes(spiPort, sendByte1, sendByte2)
    recvByte1          = recvByteArray[0]
    recvByte2          = recvByteArray[1]
    print('\n  Begin loopbackThreeBytes(),...')
    #print('')
    print('      sendBytes  = ', padDataByte(sendByte1), padDataByte(sendByte2))
    print('      recvBytes  = ', padDataByte(recvByte1), padDataByte(recvByte2))
    #print('')
    print('  End   loopbackTwoBytes().', end = '')
    return

def loopbackThreeBytes(spiPort, sendByte1, sendByte2, sendByte3):
    recvByteArray      = spiSendRecvThreeBytes(spiPort, sendByte1, sendByte2, sendByte3)
    recvByte1          = recvByteArray[0]
    recvByte2          = recvByteArray[1]
    recvByte3          = recvByteArray[2]
    print('\n  Begin loopbackThreeBytes(),...')
    print('      sendBytes  = ', padDataByte(sendByte1), padDataByte(sendByte2), padDataByte(sendByte3))
    print('      recvBytes  = ', padDataByte(recvByte1), padDataByte(recvByte2), padDataByte(recvByte3))
    #print('')
    print('  End   loopbackThreeBytes().', end = '')
    return

# *** Test SPI Loopback 1/2/3 bytes ***

def testLoopbackOneByteSpiPort00():
    print('\nBegin loopbackOneByteSpiPort00(),...', end = '')
    loopbackOneByte(spiPort00, 0x5b)
    print('\nEnd   loopbackOneByteSpiPort00().', end = '')
    return

def testLoopbackTwoBytesSpiPort00():
    print('\nBegin loopbackTwoBytesSpiPort00(),...', end = '')
    loopbackTwoBytes(spiPort00, 0x5b, 0x6b)
    print('\nEnd   loopbackTwoByte0SpiPort00().', end = '')
    return

def testLoopbackThreeBytesSpiPort00():
    print('\nBegin loopbackThreeBytesSpiPort00(),...', end = '')
    loopbackThreeBytes(spiPort00, 0x5b, 0x5c, 0x5d)
    print('\nEnd   loopbackThreeByteSpisPort00().', end = '')
    return

def testLoopbackThreeBytesSpiPort12():
    print('\nBegin loopbackThreeBytesSpiPort12(),...', end = '')
    loopbackThreeBytes(spiPort12, 0xb5, 0xc5, 0xd5)
    print('\nEnd   loopbackThreeByteSpisPo1200().', end = '')
    return

def testSpiLoopbackAll00():
    testLoopbackOneByteSpiPort00()
    print('')
    testLoopbackTwoBytesSpiPort00()
    print('')
    testLoopbackThreeBytesSpiPort00()
    return

# *** Test SPI Repeat Send Byte 0x55 ***

def repeatSendOneByte(spiPort, sendByte, pauseSeconds, repeatCount):
    print('\n\nBegin repeatSendByte(),....')
    for i in range(repeatCount):
        spiSendRecvOneByte(spiPort, sendByte)
        sleep(pauseSeconds)
    print('End   repeatSendByte().')
    return

def testRepeatSendOneByteSpiPort00():
    repeatSendOneByte(spiPort = spiPort00, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort01():
    repeatSendOneByte(spiPort = spiPort01, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort10():
    repeatSendOneByte(spiPort = spiPort10, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort11():
    repeatSendOneByte(spiPort = spiPort11, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort12():
    repeatSendOneByte(spiPort = spiPort12, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

# *** Test Results - tlfong01 2019jun12hkt2247 ***

#testSpiLoopbackAll00()            # OK
#testLoopbackThreeBytesSpiPort12() # OK
#testRepeatSendOneByteSpiPort00()  # OK
#testRepeatSendOneByteSpiPort01()  # OK

#testRepeatSendOneByteSpiPort10()  # not working !!!
#testRepeatSendOneByteSpiPort11()  # not working !!!
#testRepeatSendOneByteSpiPort12()  # OK

# *** Main Tests ***

testRepeatSendOneByteSpiPort00()  # OK
#testSpiLoopbackAll00()


# *** End of Program ***

'''
Sample ouput tlfong01 2019jun12

 RESTART: /home/pi/Python Programs/test1301/spi/spi_test_v1308_2019jun1201.py 

Begin loopbackOneByteSpiPort00(),...
  Begin loopbackOneByte(),...
      sendByte  =  0x5b
      recvByte  =  0x00
  End   loopbackOneByte().
End   loopbackOneByteSpiPort00().

Begin loopbackTwoBytesSpiPort00(),...
  Begin loopbackThreeBytes(),...
      sendBytes  =  0x5b 0x6b
      recvBytes  =  0x00 0x00
  End   loopbackTwoBytes().
End   loopbackTwoByte0SpiPort00().

Begin loopbackThreeBytesSpiPort00(),...
  Begin loopbackThreeBytes(),...
      sendBytes  =  0x5b 0x5c 0x5d
      recvBytes  =  0x00 0x00 0x00
  End   loopbackThreeBytes().
End   loopbackThreeByteSpisPort00().

Begin repeatSendByte(),....

'''

# *** End of Sample Output ***

Appendix C – SPI 10MHz Repeat Send Byte 0x5b

spi 10mhz repeat send 0x5b

Appendix D – SPI 10MHz Repeat Send Byte 0x5b Program

# Program  - spi_test_v1315_2019jul0401 tlfong01 2019jul04kt1106 
# Config   - Rpi3B+ raspberrypi 4.19.42-v7+, IDLE python 3.5.3
# Function - (1) SPI loopback 1/2/3 bytes, (2) SPI repeat send one byte

# Rpi GUI Desktop Config > Preferences > Interfaces Configuration  
# SPI, I2C, 1-Wire enable, Serial Port diaable

# Test 1   - loopBackTest - SPI port echo/loopback 1/2/3 bytes.
# Function - Send 1/2/3 bytes to MOSI and read it back from MISO. 
# Setup    - Connet MOSI pin to MISO pin to form echo loop.

# Test 2   - repeat send one byte - SPI port repeat send one byte (need a scope to display waveforms).
# Function - repeat send data byte 0x5b and use scope to display waveforme CLK. MOSI, MISO, CS0, CS1. 
# Setup    - nil

# dtoverlay to enable SPI Channal 0 and Channal 1
# sudo nano /boot/config.txt dtoverlay setting 
# dtparam=i2c_arm=on
# dtparam=spi=on
# dtoverlay=spi1-3cs

# /dev/spi listing
# $ ls -l /dev/spi*
# should show the following:
# 1. /dev/spidev0.0
# 2. /dev/spidev0.1
# 3. /dev/spidev1.0
# 4. /dev/spidev1.1
# 5. /dev/spidev1.2

from   time import sleep
import spidev

# *** SPI Setup/Config ***

spiPort00 = spidev.SpiDev()
spiPort00.open(0, 0)
# spiPort00.max_speed_hz   =  100000  # 0.1 MHz (100 kHz)
# spiPort00.max_speed_hz   = 1000000  #   1 MHz
spiPort00.max_speed_hz     = 5000000  #   5 MHz 

spiPort01 = spidev.SpiDev()
spiPort01.open(0, 1)
spiPort01.max_speed_hz = 100000

# *** Not tested - tlfong01  2019jul03hkt1047 ***

'''
spiPort10 = spidev.SpiDev()
spiPort10.open(1, 0)
spiPort10.max_speed_hz = 100000

spiPort11 = spidev.SpiDev()
spiPort11.open(1, 1)
spiPort11.max_speed_hz = 100000

spiPort12 = spidev.SpiDev()
spiPort12.open(1, 2)
spiPort12.max_speed_hz = 100000
'''

# *** Spi port functions ***

def setSpiPortSpeed(spiPortNum, speedName):
    spiPortList[spiPortNum].max_speed_hz = speedDict[speedName]
    return

def closeSpiPortAll():
    for i in spiPortList:
        i.close()
    return

# ** Pretty Print Functions ***

def padDataByte(dataByte):
    unPadString = (hex(dataByte)[2:])
    if (len(unPadString) != 2):
        unPadString = '0' + unPadString
    padString = '0x' + unPadString
    return padString

def printTitleDataByte(title, dataByte):
    print(title, padDataByte(dataByte))
    return

# *** SPI Write/Read/Loopback 1/2/3 Bytes ***

# *** SPI Send/Receive 1/2/3 Bytes ***

def spiSendRecvOneByte(spiPort, sendByte):
    sendByteArray = [sendByte]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

def spiSendRecvTwoBytes(spiPort, sendByte1, sendByte2):
    sendByteArray = [sendByte1, sendByte2]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

def spiSendRecvThreeBytes(spiPort, sendByte1, sendByte2, sendByte3):
    sendByteArray = [sendByte1, sendByte2, sendByte3]
    recvByteArray = spiPort.xfer(sendByteArray)    
    return recvByteArray

# *** Loopback 1/2/3 Bytes ***

def loopbackOneByte(spiPort, sendByte):
    recvByteArray     = spiSendRecvOneByte(spiPort, sendByte)
    recvByte          = recvByteArray[0]
    print('\n  Begin loopbackOneByte(),...')
    printTitleDataByte('      sendByte  = ', sendByte)
    printTitleDataByte('      recvByte  = ', recvByte)
    #print('')
    print('  End   loopbackOneByte().', end = '')
    return

def loopbackTwoBytes(spiPort, sendByte1, sendByte2):
    recvByteArray     = spiSendRecvTwoBytes(spiPort, sendByte1, sendByte2)
    recvByte1          = recvByteArray[0]
    recvByte2          = recvByteArray[1]
    print('\n  Begin loopbackThreeBytes(),...')
    #print('')
    print('      sendBytes  = ', padDataByte(sendByte1), padDataByte(sendByte2))
    print('      recvBytes  = ', padDataByte(recvByte1), padDataByte(recvByte2))
    #print('')
    print('  End   loopbackTwoBytes().', end = '')
    return

def loopbackThreeBytes(spiPort, sendByte1, sendByte2, sendByte3):
    recvByteArray      = spiSendRecvThreeBytes(spiPort, sendByte1, sendByte2, sendByte3)
    recvByte1          = recvByteArray[0]
    recvByte2          = recvByteArray[1]
    recvByte3          = recvByteArray[2]
    print('\n  Begin loopbackThreeBytes(),...')
    print('      sendBytes  = ', padDataByte(sendByte1), padDataByte(sendByte2), padDataByte(sendByte3))
    print('      recvBytes  = ', padDataByte(recvByte1), padDataByte(recvByte2), padDataByte(recvByte3))
    #print('')
    print('  End   loopbackThreeBytes().', end = '')
    return

# *** Test SPI Loopback 1/2/3 bytes ***

def testLoopbackOneByteSpiPort00():
    print('\nBegin loopbackOneByteSpiPort00(),...', end = '')
    loopbackOneByte(spiPort00, 0x5b)
    print('\nEnd   loopbackOneByteSpiPort00().', end = '')
    return

def testLoopbackTwoBytesSpiPort00():
    print('\nBegin loopbackTwoBytesSpiPort00(),...', end = '')
    loopbackTwoBytes(spiPort00, 0x5b, 0x6b)
    print('\nEnd   loopbackTwoByte0SpiPort00().', end = '')
    return

def testLoopbackThreeBytesSpiPort00():
    print('\nBegin loopbackThreeBytesSpiPort00(),...', end = '')
    loopbackThreeBytes(spiPort00, 0x5b, 0x5c, 0x5d)
    print('\nEnd   loopbackThreeByteSpisPort00().', end = '')
    return

def testLoopbackThreeBytesSpiPort12():
    print('\nBegin loopbackThreeBytesSpiPort12(),...', end = '')
    loopbackThreeBytes(spiPort12, 0xb5, 0xc5, 0xd5)
    print('\nEnd   loopbackThreeByteSpisPo1200().', end = '')
    return

def testSpiLoopbackAll00():
    testLoopbackOneByteSpiPort00()
    print('')
    testLoopbackTwoBytesSpiPort00()
    print('')
    testLoopbackThreeBytesSpiPort00()
    return

# *** Test SPI Repeat Send Byte 0x5b ***

# *** Initialized SPI Frequency ***

def repeatSendOneByte(spiPort, sendByte, pauseSeconds, repeatCount):
    print('\n\nBegin repeatSendByte(),....')
    for i in range(repeatCount):
        spiSendRecvOneByte(spiPort, sendByte)
        sleep(pauseSeconds)
    print('End   repeatSendByte().')
    return

def testRepeatSendOneByteSpiPort00():
    repeatSendOneByte(spiPort = spiPort00, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort01():
    repeatSendOneByte(spiPort = spiPort01, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort10():
    repeatSendOneByte(spiPort = spiPort10, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort11():
    repeatSendOneByte(spiPort = spiPort11, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

def testRepeatSendOneByteSpiPort12():
    repeatSendOneByte(spiPort = spiPort12, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000)
    return

# *** 5MHz and 10MHz Tests ***

def testRepeatSendOneByteSpi10MhzPort00():
    spiPort00.max_speed_hz =10000000
    repeatSendOneByte(spiPort = spiPort00, sendByte = 0x5b, pauseSeconds = 0.001, repeatCount = 200000000)
    return

# *** Test Results - tlfong01 2019jun12hkt2247 ***

#testSpiLoopbackAll00()            # OK
#testLoopbackThreeBytesSpiPort12() # OK
#testRepeatSendOneByteSpiPort00()  # OK
#testRepeatSendOneByteSpiPort01()  # OK

#testRepeatSendOneByteSpiPort10()  # not working !!!
#testRepeatSendOneByteSpiPort11()  # not working !!!
#testRepeatSendOneByteSpiPort12()  # OK

# *** Main Tests ***

#testSpiLoopbackAll00()
#testRepeatSendOneByteSpiPort00()  # OK

testRepeatSendOneByteSpi10MhzPort00()

# *** End of SPI Test Program ***

# *** Sample Output 2019jun12 ***

'''
 RESTART: /home/pi/Python Programs/test1301/spi/spi_test_v1308_2019jun1201.py 

Begin loopbackOneByteSpiPort00(),...
  Begin loopbackOneByte(),...
      sendByte  =  0x5b
      recvByte  =  0x00
  End   loopbackOneByte().
End   loopbackOneByteSpiPort00().

Begin loopbackTwoBytesSpiPort00(),...
  Begin loopbackThreeBytes(),...
      sendBytes  =  0x5b 0x6b
      recvBytes  =  0x00 0x00
  End   loopbackTwoBytes().
End   loopbackTwoByte0SpiPort00().

Begin loopbackThreeBytesSpiPort00(),...
  Begin loopbackThreeBytes(),...
      sendBytes  =  0x5b 0x5c 0x5d
      recvBytes  =  0x00 0x00 0x00
  End   loopbackThreeBytes().
End   loopbackThreeByteSpisPort00().

Begin repeatSendByte(),....

'''

# *** End of Sample Output ***

Appendix C – SPI 1 Learning Notes

SPI1 (Auxiliary SPI) Config and Kernel Module

SPI1 (an auxiliary SPI device) is supported in raspbian kernels from 4.4 onwards.

SPI1 uses GPIO16-21 (by default) and is found on all 40 pin rPi’s to date.

It has up to three CS lines allowing you to control 3 devices natively. The kernel module allows for the CS lines to be repositioned on any free GPIO pin via the appropriate options passed to the dtoverlay.

The device reports supporting the following Linux SPIdev options:

SPI_CS_HIGH (CS inverted)

SPI_NO_CS (Device is signalled elsewhere) – this option is utilised for the GPIO CS implementation the kernel driver now uses.

The implementation of SPI1 allows for a fair bit of flexibility. There three overlays, a 1CS, 2CS and 3CS option. If you only need to control one device use the 1CS option. You can expand to more CS lines later

enable spi1 with a single CS line dtoverlay=spi1-1cs

enable spi1 with two CS lines dtoverlay=spi1-2cs

enable spi1 with three CS lines dtoverlay=spi1-3cs

Additionally the CS lines are now software controlled so they can be reconfigured to any available GPIO pin. See the /boot/overlays/README for details.

Kernel Module

The module is called spi_bcm2835.

If SPI1 is enabled in the config.txt the kernel module should load automatically after a reboot. Check with lsmod.

$ lsmod | grep spi spi_bcm2835 7216 0

If it doesn’t appear make sure this isn’t blacklisted in/etc/modprobe.d/raspi-blacklist.conf. When the module is running you will find device nodes have been created as per the dtoverlay in the the config.txt.

crw-rw—- 1 root spi 153, 0 Jan 11 15:47 spidev1.0 crw-rw—- 1 root spi 153, 1 Jan 11 15:47 spidev1.1

System Config

You should already have a user group called ‘spi’ which has read/write access to the device nodes. Add yourself and any other accounts that need access to this group if you have not already done so.

sudo usermod -a -G spi

  • Hey. I tested your code. I got voltage somewhere around 1.632 – Oncetwice 12 hours ago
  • Well, of course there is something wrong with 1.632V. Usually I swap things to troubleshoot. For example, I might try SPI(1, 2) which uses different CLK, MOSI, and CS pins. Or I might try UART which also uses different pins. BTW, I assume your SPI wires are less than 1 metre, not 100 metres! 🙂 – tlfong01 5 hours ago  

Categories: Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: