Easyelectronics.ru

Электроника для всех
Текущее время: 26 ноя 2020, 19:41

Часовой пояс: UTC + 5 часов



JLCPCB – Прототипы печатных плат за $2/5шт. два слоя. $5/5шт. четыре слоя
Крупнейший производитель печатных плат и прототипов. Более 600000 клиентов и свыше 10000 заказов в день!
Получите скидку на почтовую отправку при первом заказе в JLCPCB!

Начать новую тему Эта тема закрыта, вы не можете редактировать и оставлять сообщения в ней.  [ Сообщений: 102 ]  На страницу 1, 2, 3, 4, 5  След.
Автор Сообщение
 Заголовок сообщения: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 05:30 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Хочу обратить ваше внимание на свое хобби, часть которого - разработка ядра операционной системы для ATmega328 и подобных на ассемблере.

Вот ссылка на гитхаб https://github.com/w5277c/core5277

Проект еще очень сырой, некоторый код (в основном драйвера) не актуализирован под последние изменения процедур ядра.
Тем не менее можно поэкспериментировать с многозадачностью, логированием и поработать с устройствами (есть рабочие примеры).

Как в рамках ядра, так и в рамках всего проекта 5277, мне нужны заинтересованные для стимула в дальнейшей разработке.


Вот пример кода:
;-----------------------------------------------------------------------------------------------------------------------
;Разработчиком и полноправным владельцем данного исходного кода является Удовиченко Константин Александрович,
;емайл:w5277c@gmail.com, по всем правовым вопросам обращайтесь на email.
;-----------------------------------------------------------------------------------------------------------------------
;19.09.2020 w5277c@gmail.com Начало
;-----------------------------------------------------------------------------------------------------------------------
;BUILD: avra -I ../../ main.asm

.INCLUDE "./inc/devices/atmega328.inc"
.SET REALTIME = 0 ;0-1
.SET TIMERS = 1 ;0-4
.SET BUFFER_SIZE = 0x00;Размер общего буфера
.SET LOGGING_PORT = PC0 ;PA0-PC7
;---INCLUDES---------------------------------------------
.INCLUDE "core5277.asm"
;Блок драйверов
.include "./inc/drivers/uart_h.inc"
;---
;Блок задач
;---
;Дополнительно
.include "./inc/io/log_bytes.inc"
.include "./inc/io/logstr_new_line.inc"
.include "./inc/mem/eeprom_write_byte.inc"
.include "./inc/mem/eeprom_read_byte.inc"
.include "./inc/core/wait_1s.inc"
.include "./inc/mem/ram_fill8.inc"
;---

;---CONSTANTS--------------------------------------------
;Идентификаторы драйверов(0-7|0-15)
.EQU PID_UART_DRV = 0|(1<<CORE5277_PROCID_OPT_DRV)
;Идентификаторы задач(0-3|0-15)
.EQU PID_TASK = 0
;Идентификаторы таймеров
.EQU TID_UART = 0
;--------------------------------------------------------;Выполняемый код при старте контроллера
MAIN:
CLI
;Инициализация стека
LDI TEMP,high(RAMEND)
STS SPH,TEMP
LDI TEMP,low(RAMEND)
STS SPL,TEMP

;Инициализация ядра
MCALL CORE5277_INIT

;Инициализация UART
LDI PID,PID_UART_DRV
LDI ZH,high(DRV_HUART_INIT)
LDI ZL,low(DRV_HUART_INIT)
LDI TEMP_H,PD4
LDI TEMP_L,0xff
LDI ACCUM,TID_UART
LDI FLAGS,(1<<DRV_HUART_OPT_BREAK)
LDI YH,DRV_HUART_BAUDRATE_9600
MCALL CORE5277_CREATE

;Инициализация задачи тестирования
LDI PID,PID_TASK
LDI ZH,high(TASK__INIT)
LDI ZL,low(TASK__INIT)
MCALL CORE5277_CREATE

MJMP CORE5277_START

TASK_DATA:
.db "Hello world!",0x0d,0x0a,0x00

;--------------------------------------------------------;Задача
TASK__INIT:
LDI ACCUM,0x21
MCALL CORE5277_RAM_REALLOC

MCALL CORE5277_READY
;--------------------------------------------------------
TASK__INFINITE_LOOP:
LDI LOOP_CNTR,0x21
LDI TEMP,0x00
MOV XH,ZH
MOV XL,ZL
MCALL CORE5277_RAM_FILL8

LDI TEMP,PID_UART_DRV
LDI YH,high(TASK_DATA)|0x80
LDI YL,low(TASK_DATA)
LDI TEMP_EH,14
LDI TEMP_EL,0x20
LDI TEMP_H,0x00
LDI TEMP_L,0x00
MCALL CORE5277_EXEC
CPI TEMP_H,DRV_HUART_ST_READY
BRNE TASK__INFINITE_LOOP

MOV YH,ZH
MOV YL,ZL
MCALL CORE5277_LOG_STR
RJMP TASK__INFINITE_LOOP


Последний раз редактировалось w5277c 23 сен 2020, 11:48, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 07:58 
Старожил
Аватара пользователя

Зарегистрирован: 28 дек 2011, 11:24
Сообщения: 4344
Откуда: г. Липецк
Вы с самого начала запутываете программиста. Почему секция инициализации имеет метку "Main"? Всегда встречал "Init" или "Reset".


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 08:14 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
anakost писал(а):
Вы с самого начала запутываете программиста. Почему секция инициализации имеет метку "Main"? Всегда встречал "Init" или "Reset".

Вы серьезно считаете, что программиста можно запутать подобным?

Насколько я помню в шаблоне Atmel Studio как раз написано main.

Более того, этот блок является главным, поэтому main.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 10:54 
Старожил

Зарегистрирован: 08 июл 2013, 17:00
Сообщения: 779
Цитата:
Всегда встречал "Init" или "Reset".

Аналогично.
Главное- это то, что ты пишешь, а не то, что стартует первым. Как в языке Си называется функция, с которой начинается выполнение
Код:
пользовательского
кода?
Называй как хочешь, только вот из-за таких крючков, о которые спотыкается глаз и разум, у людей будет возникать скрытое неприятие. Ну и тратить время на разгадывание шарад типа этой тоже остужает пыл изучать предложенное. Подумай над этим.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 11:40 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
tonyk писал(а):
Цитата:
Всегда встречал "Init" или "Reset".

Аналогично.
Главное- это то, что ты пишешь, а не то, что стартует первым. Как в языке Си называется функция, с которой начинается выполнение
Код:
пользовательского
кода?
Называй как хочешь, только вот из-за таких крючков, о которые спотыкается глаз и разум, у людей будет возникать скрытое неприятие. Ну и тратить время на разгадывание шарад типа этой тоже остужает пыл изучать предложенное. Подумай над этим.


Мне очень тяжело понять что Вы написали, и это несколько странно, если предположить, что это адресовано мне с претензией к названию главной процедуры.

Я заглянул в шаблон официальной среды разработки Atmel Studio, там главная процедура называется start, ни Init и ни Reset, и даже не Main - start.
Хотя во многих языках главный блок программы называется именно main (С#,C/C++,Java и прочее)
Глупо конечно обсуждать такие мелочи, однако, данная моя процедура является главной, это не процедура инициализации, и не обязательно процедура старта, а именно главная процедура в которой описываются основные компоненты проекта.

Если же для кого-то это принципиально и из-за этого тяжело читать код, может быть Вам просто не стоит называть себя разработчиком? Может быть Вы просто шаблонщик?

Более того, я разрабатываю инструмент и предлагаю им воспользоваться, изучать Вас это никто не заставляет.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 11:52 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
tonyk писал(а):
Цитата:
Всегда встречал "Init" или "Reset".

Аналогично.
Главное- это то, что ты пишешь, а не то, что стартует первым. Как в языке Си называется функция, с которой начинается выполнение
Код:
пользовательского
кода?
Называй как хочешь, только вот из-за таких крючков, о которые спотыкается глаз и разум, у людей будет возникать скрытое неприятие. Ну и тратить время на разгадывание шарад типа этой тоже остужает пыл изучать предложенное. Подумай над этим.


Кажется я понял в чем дело, кто-то AVR с STM32 перепутал, не увидел процедуры инициализации ;)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 12:06 
Старожил

Зарегистрирован: 08 авг 2013, 09:43
Сообщения: 2944
Соглашусь с комментаторами в том, что MAIN эту часть называть не стоило.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 12:37 
Заглядывает иногда

Зарегистрирован: 14 апр 2014, 11:41
Сообщения: 197
Откуда: Минск Беларусь
w5277c, вы бы лучше написали для чего нужна ваша операционка?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 16:20 
Заглядывает иногда

Зарегистрирован: 14 апр 2014, 11:41
Сообщения: 197
Откуда: Минск Беларусь
w5277c писал(а):
Yoda писал(а):
w5277c, вы бы лучше написали для чего нужна ваша операционка?


У меня есть пост в ЖЖ https://5277.livejournal.com/33456.html

По сути я ее пишу для снижения трудозатрат разработки на ассемблере, некоторой переносимости проекта на разные МК.
Ну и конечно, в первую очередь, для решения своих задач, в основном которые сводятся к реализации типа умных конечных устройств (различным датчикам, шлюзам интерфейсов, исполнительным устройствам)


А что мешает всем этим датчикам, шлюзам и исполнительным устройствам работать без вашей ОС? В атмеге и так ресурсов кот наплакал, а вы туда ещё ОС пихаете.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 16:46 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Yoda писал(а):
А что мешает всем этим датчикам, шлюзам и исполнительным устройствам работать без вашей ОС? В атмеге и так ресурсов кот наплакал, а вы туда ещё ОС пихаете.

А Вы пробовали на атмеге параллеьно обрабатывать запросы по UART, опрашивать DS18B20, AM2301, контакты открытия двери, одновременно работать с GSM модемом по программному UART через AT команды, работать с RTC часами и EEPROM? Я пробовал, без особых проблем, благодаря первой версии подобного ядра.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 19:57 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Цитата:
Вам правильно указали по поводу смешивания в проекте кода инициализации периферии отдельно взятого контроллера и логики решения задачи.


Вы так считаете? Допущу, что Вы адекватный.
Скажите, где у меня в этом блоке инициализация перефирии?

Цитата:
(кто то, что бы такого не делать при запуске кода задачи на другом контроллере ввёл понятие HAL и спрятал "кишки" железа в этом слое)

Вы не забыли, что мы говорим про AVR, для Вас это что-нибудь значит?

Вы смотрели что я там понаписал, или сделали выводы на базе даже не знаю чего? Шаблонов своих?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:01 
Старожил

Зарегистрирован: 27 апр 2013, 13:53
Сообщения: 1443
Del.
\ Не только модератор может тереть сообщения :)


Последний раз редактировалось KPG 23 сен 2020, 20:24, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:05 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
KPG писал(а):
w5277c писал(а):
Цитата:
Вам правильно указали по поводу смешивания в проекте кода инициализации периферии отдельно взятого контроллера и логики решения задачи.


Вы так считаете? Допущу, что Вы адекватный.
Скажите, где у меня в этом блоке инициализация перефирии?

А, это что?
Show


Это инициализация процедур которые я называю драйвера, любых, это не обязательно периферия. И я вижу этот код именно пользовательским, он может быть где угодно, в том числе и в задаче.

А инициализация именно периферии выполняется в драйвере, если он ее использует.


Последний раз редактировалось w5277c 23 сен 2020, 20:28, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:06 
Заглядывает иногда

Зарегистрирован: 10 сен 2020, 21:37
Сообщения: 148
А давайте автор темы сам будет соблюдать приличия и уважительно относиться к присутствующим? Критику надо уметь принимать. Тем более, что критика была более чем уместна.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:15 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Может быть я не прав, но мне кажется, что комментаторы немного путают AVR и STM32(вроде как там в начале необходимо настроить периферию). С AVR все гораздо проще, может это Вас сбивает с толку? И Вы не в ту ветку зашли?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:17 
Супермодератор
Аватара пользователя

Зарегистрирован: 26 янв 2010, 22:19
Сообщения: 6802
Откуда: Из тех... Из бывших...
Пельмень Мясной писал(а):
А давайте автор темы сам будет соблюдать приличия и уважительно относиться к присутствующим?

Давайте. А ещё давайте договоримся о терминах. Если тс предложил свою трактовку, не стоит до хрипоты спорить о ее приемлемости. Давайте, если уж на то пошло, вы прежде чем выискивать косяки в названии файлов попробуете поюзать, а уж потом критиковать удобство пользования, функциональность, глючность, тормознутость. Если камень неинтересен лично вам, это не значит, что он никому не интересен.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:18 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
STT писал(а):
Пельмень Мясной писал(а):
А давайте автор темы сам будет соблюдать приличия и уважительно относиться к присутствующим?

Давайте. А ещё давайте договоримся о терминах. Если тс предложил свою трактовку, не стоит до хрипоты спорить о ее приемлемости. Давайте, если уж на то пошло, вы прежде чем выискивать косяки в названии файлов попробуете поюзать, а уж потом критиковать удобство пользования, функциональность, глючность, тормознутость. Если камень неинтересен лично вам, это не значит, что он никому не интересен.


Полностью согласен, спасибо.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:20 
Супермодератор
Аватара пользователя

Зарегистрирован: 26 янв 2010, 22:19
Сообщения: 6802
Откуда: Из тех... Из бывших...
P.S. Всех, включая тс, прошу воздержаться от личностных оценок оппонентов. Есть кнопка "игнор" на крайний случай.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:39 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Суть здесь вот в чем.

Программист работает на уровне задачи т.е. описывает логику задачи.
Все взаимодействие с периферией выполняется через процедуры драйверов.

В ОС есть различные процедуры, которые отвязывают логику задач от реального железа, например есть программные таймеры или процедуры изменения векторов прерываний налету (но это уже ближе к драйверу).
Даже вместо безусловных переходов и вызовов процедур зачастую нужно использовать макросы.
Так как в некоторых МК нет CALL и JMP, а в других МК возникли сложности с линковкой(?) при использовании RCALL и RJMP.

И чем дальше, тем будет больше процедур и драйверов.

Таким образом код можно легко перенести на разные AVR МК.
Конечно здесь псевдопараллельное выполнение (у нас одноядерный процессор), переключение задач выполняется каждый тик = 2мс.

Главное преимущество в том, что задача имеет свой независимый стек и свои независимые 16 верхних регистров.
Есть механизмы блокирующие засыпание задачи, выжидания определенного времени или ресурса
Вам не потребуется ломать голову как распределять регистры для обработки нескольких датчиков.
Вам не придется ломать голову как выдерживать тайминги.
Зачастую Вам всего-лишь нужно скормить необходимые параметры драйверу и получить ответ.
Все просто.

И да, можно использовать прямые обращения к периферии, например к незадействованным таймерам.
Но тогда придется попрощаться с переносимостью на другие МК.
Ну или использовать ifdef и описывать все варианты.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 20:52 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
А еще каждая процедура вынесена в отдельный файл.
Я не смог решить проблемы из коробки - как исключить не используемый код.
Поэтому ввел инклуды. В каждом инклуде проверяется наличие уже подгруженной процедуры.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 21:00 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Ну и работа с памятью тоже есть.
Можно выделять, перевыделять, уменьшать, увеличивать объем используемой памяти в задаче или драйвере, конечно налету.
Но, выделенный блок не может превышать 255 байт.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 21:01 
Старожил

Зарегистрирован: 23 янв 2016, 15:37
Сообщения: 1344
w5277c писал(а):
Вам не придется ломать голову как выдерживать тайминги.
Зачастую Вам всего-лишь нужно скормить необходимые параметры драйверу и получить ответ.
Все просто.

На AVR есть команды которые позволяют установить/сбросить бит порта за 2 такта, у тебя аналогичная операция выглядит так:
Show

В BITNUM_TO_NUM еще немного в цикле покрутится, итого получается под сотню тактов. На месте потенциального пользователя я бы насчет выдерживания таймингов точно переживал :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 21:18 
Заглядывает иногда

Зарегистрирован: 23 сен 2020, 05:17
Сообщения: 41
Reflector писал(а):
w5277c писал(а):
Вам не придется ломать голову как выдерживать тайминги.
Зачастую Вам всего-лишь нужно скормить необходимые параметры драйверу и получить ответ.
Все просто.

На AVR есть команды которые позволяют установить/сбросить бит порта за 2 такта, у тебя аналогичная операция выглядит так:
Show

В BITNUM_TO_NUM еще немного в цикле покрутится, итого получается под сотню тактов. На месте потенциального пользователя я бы насчет выдерживания таймингов точно переживал :)


Да, вынужденная мера. SBI, CBI и прочее не применимы с унифицированной моделью работы с портами. Может завтра подробнее раскажу.

Насколько я помню, командам работы с портами нельзя указать порт через регистр, в этом вся проблема.
А мне необходимо дать возможность передавать порты программно.

Тактов конечно татится много. Альтернативы пока не вижу. Однако, на 16МГц драйвера успевают обрабатывать тот-же 1wire и AM2301.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 21:42 
Старожил

Зарегистрирован: 19 мар 2020, 00:29
Сообщения: 270
Откуда: VRN-сити
А не проще просто сесть и написать прогу на конкретный проц под конкретную задачу с нуля, ну или не с нуля , ведь всё равно у каждого есть задел и не городить огород на таких тщедушных камушках. Сам любитель восьмибитов , но городить такой огород на них, как то извращением попахивает, ну в прочем это моё сугубо личное мнение :)


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Ядро на ассемблере для Atmega328 и прочих
СообщениеДобавлено: 23 сен 2020, 23:09 
Старожил

Зарегистрирован: 23 янв 2016, 15:37
Сообщения: 1344
w5277c писал(а):
Да, вынужденная мера. SBI, CBI и прочее не применимы с унифицированной моделью работы с портами.

Я сам люблю чтоб было просто и универсально, потому пишу на C++, но там даже если передать в некий класс несколько десятков пинов, то все будет максимально эффективно. Писал бы под AVR, генерилась бы одна SBI или CBI. А на ассме обычно пишут ради максимальной эффективности(или потому что ничего другого не знают), в таком случае настолько медленная работа с портами нивелирует одно из основных преимуществ...
Кстати, если у тебя вытесняющая RTOS, то так делать нельзя:
Код:
   LD TEMP,Z
   OR TEMP,ACCUM
   ST Z,TEMP

Это неатомарный RMW над портом, переключение на другую задачу может произойти после чтения значения PORTx, но до записи нового значения, затем другая задача может записать в PORTx что-то свое и тогда старое прочитанное в TEMP значение уже не будет актуальным...


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Эта тема закрыта, вы не можете редактировать и оставлять сообщения в ней.  [ Сообщений: 102 ]  На страницу 1, 2, 3, 4, 5  След.


Часовой пояс: UTC + 5 часов


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB